commit c17f4c38e9725686cae45323b342dd26d470c63e Author: root <13910913995@163.com> Date: Fri May 30 09:58:52 2025 +0800 Initial commit diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..359bb53 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml diff --git a/.idea/StdProject.iml b/.idea/StdProject.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/StdProject.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..b56de12 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..dfc8d74 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..5a2f139 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..ac9352c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..fbb69cc --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/backend/db/db_mysql.sql b/backend/db/db_mysql.sql new file mode 100644 index 0000000..52e6b58 --- /dev/null +++ b/backend/db/db_mysql.sql @@ -0,0 +1,242 @@ +/* + Navicat Premium Dump SQL + + Source Server : 华为云-mysql数据库 + Source Server Type : MySQL + Source Server Version : 80403 (8.4.3) + Source Host : 121.37.111.42:3306 + Source Schema : gisbi-demodb + + Target Server Type : MySQL + Target Server Version : 80403 (8.4.3) + File Encoding : 65001 + + Date: 30/05/2025 08:58:25 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for app_application +-- ---------------------------- +DROP TABLE IF EXISTS `app_application`; +CREATE TABLE `app_application` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `type` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '01' COMMENT '应用类型 01-数据展示分析 ', + `code` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用编号 自动生成:000001', + `name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '应用名称', + `simplename` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用简称', + `createdate` datetime NULL DEFAULT NULL COMMENT '创建日期', + `description` varchar(600) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用描述', + `image` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '应用图片 base64存储', + `appconfig` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '应用配置 JSON格式存储其他配置相关信息', + `dbconfig` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '数据库配置 JSON格式存储数据库信息配置(数据库用于存储此应用系统的所有配置数据)', + `organization` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户单位 使用这个应用系统的组织单位', + `status` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '状态 01-初始创建 02-正常运行 09-已停用', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime NULL DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用系统' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_dictionary +-- ---------------------------- +DROP TABLE IF EXISTS `app_dictionary`; +CREATE TABLE `app_dictionary` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `orderno` int NOT NULL COMMENT '顺序号', + `dictcode` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典编码', + `dictname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典名称', + `dictdata` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '字典数据 JSON数组[{\"code\":\"01\",\"name\":\"字典值\"}]', + `lastmodifydate` datetime NULL DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用-数据字典' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_menu +-- ---------------------------- +DROP TABLE IF EXISTS `app_menu`; +CREATE TABLE `app_menu` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `type` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单类型 01-菜单', + `code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单编号', + `orderno` int NULL DEFAULT NULL COMMENT '同级序号', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单名称', + `icon` varchar(9000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单图标 base64存储', + `islink` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否外链 0-非外部 1-是外链', + `url` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '菜单URL 内部资源页面URL访问地址', + `module_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '模块ID 菜单关联的模块ID', + `parentid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '父级菜单ID 顶级为0', + `isdisplay` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '是否显示 0-不显示 1-显示', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime NULL DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用系统_菜单' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_module +-- ---------------------------- +DROP TABLE IF EXISTS `app_module`; +CREATE TABLE `app_module` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '名称', + `pid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '父级ID 父级模块', + `level` int NULL DEFAULT NULL COMMENT '层级', + `node_type` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '节点类型 01-目录 02-模块', + `type` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '类型 01-登录页面 02-主框架页面 03-GIS大屏页面 04-二级弹窗页面 05-数据填报页面 06-文档资源页面09-自定义页面', + `canvas_style_data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '样式数据', + `component_data` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '组件数据', + `status` int NULL DEFAULT 1 COMMENT '状态 0-未发布 1-已发布', + `self_watermark_status` int NULL DEFAULT 0 COMMENT '是否单独打开水印 0-关闭 1-开启', + `sort` int NULL DEFAULT 0 COMMENT '排序 目录内的排序号', + `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间', + `create_by` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建人', + `update_time` datetime NULL DEFAULT NULL COMMENT '更新时间', + `update_by` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新人', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + `source` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '数据来源', + `delete_flag` tinyint NULL DEFAULT 0 COMMENT '删除标志', + `delete_time` datetime NULL DEFAULT NULL COMMENT '删除时间', + `delete_by` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '删除人', + `version` int NULL DEFAULT 0 COMMENT '可视化资源版本', + `content_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '内容标识', + `check_version` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1' COMMENT '内容检查标识', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用_系统模块' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_optlog +-- ---------------------------- +DROP TABLE IF EXISTS `app_optlog`; +CREATE TABLE `app_optlog` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `usercode` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '用户账号', + `username` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '用户名称', + `opttype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '操作类型 00-登录 01-新增 02-修改 03-删除 06-查询 09其他', + `module` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '模块名称', + `description` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '日志描述', + `method` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '操作方法', + `params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL COMMENT '方法参数', + `logtime` datetime NULL DEFAULT NULL COMMENT '创建时间', + `requestip` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '请求IP', + `browser` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '浏览器类型', + PRIMARY KEY (`id`) USING BTREE, + INDEX `log_create_time_index`(`logtime` ASC) USING BTREE, + INDEX `inx_log_type`(`opttype` ASC) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin COMMENT = '系统操作日志' ROW_FORMAT = Dynamic; + +-- ---------------------------- +-- Table structure for app_organization +-- ---------------------------- +DROP TABLE IF EXISTS `app_organization`; +CREATE TABLE `app_organization` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `orgtype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组织类型:01-公司 02-部门', + `orgcode` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组织编号', + `orgname` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组织名称', + `parentid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '上级ID', + `manager` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组织负责人', + `description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '组织详情', + `address` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系地址', + `contact_phone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系电话', + `contact_person` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系人', + `isvaild` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '是否有效 1-是 0-否', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime NULL DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用系统_用户组织' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_role +-- ---------------------------- +DROP TABLE IF EXISTS `app_role`; +CREATE TABLE `app_role` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `rolecode` varchar(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色编号 系统生成,三位编号', + `rolename` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色名称', + `type` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色类别 1-应用管理员 2-应用普通用户', + `description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '角色描述', + `isvaild` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '是否有效 1-是 0-否', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '最近修改者', + `lastmodifydate` datetime NOT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用系统_系统角色' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS `app_role_menu`; +CREATE TABLE `app_role_menu` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `roleid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色id', + `menuid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统角色-数据权限对照' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_role_users +-- ---------------------------- +DROP TABLE IF EXISTS `app_role_users`; +CREATE TABLE `app_role_users` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `roleid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色id', + `userid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统角色-用户对照' ROW_FORMAT = DYNAMIC; + +-- ---------------------------- +-- Table structure for app_user +-- ---------------------------- +DROP TABLE IF EXISTS `app_user`; +CREATE TABLE `app_user` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '应用ID 关联应用系统', + `orgid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '所属组织', + `usertype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户类型 0-管理员 1-普通用户', + `username` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名称 用户名称(账号)', + `nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户昵称(中文)', + `password` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '登录密码', + `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱', + `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号', + `avatar` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '用户头像 base64存储用户头像', + `status` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '1' COMMENT '状态 1-有效 0-停用', + `pwdvalidperiod` int NULL DEFAULT 90 COMMENT '密码有限期 密码有限期(天)', + `failednum` int NULL DEFAULT 0 COMMENT '登录失败次数 允许的登录失败次数', + `loginip` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户指定登录IP 如果设置了IP,则只允许IP用户登录', + `failedlocktime` datetime NULL DEFAULT NULL COMMENT '登录失败锁定时间', + `pwdresettime` datetime NULL DEFAULT NULL COMMENT '密码修改时间', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime NULL DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '应用系统_系统用户' ROW_FORMAT = DYNAMIC; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/backend/db/db_sqllite.sql b/backend/db/db_sqllite.sql new file mode 100644 index 0000000..53c751c --- /dev/null +++ b/backend/db/db_sqllite.sql @@ -0,0 +1,243 @@ +/* +Navicat SQLite Data Transfer + +Source Server : project +Source Server Version : 30808 +Source Host : :0 + +Target Server Type : SQLite +Target Server Version : 30808 +File Encoding : 65001 + +Date: 2025-05-30 09:13:56 +*/ + +PRAGMA foreign_keys = OFF; + +-- ---------------------------- +-- Table structure for app_application +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_application"; +CREATE TABLE "app_application" ( +"id" TEXT(40) NOT NULL, +"type" TEXT(2), +"code" TEXT(6), +"name" TEXT(200) NOT NULL, +"simplename" TEXT(100), +"createdate" TEXT, +"description" TEXT(600), +"image" TEXT, +"appconfig" TEXT, +"dbconfig" TEXT, +"organization" TEXT(200), +"status" TEXT(20), +"lastmodifier" TEXT(40), +"lastmodifydate" TEXT, +"custom1" TEXT(100), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_dictionary +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_dictionary"; +CREATE TABLE "app_dictionary" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"orderno" INTEGER NOT NULL, +"dictcode" TEXT(40) NOT NULL, +"dictname" TEXT(100) NOT NULL, +"dictdata" TEXT, +"lastmodifydate" TEXT, +"custom1" TEXT(1000), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_menu +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_menu"; +CREATE TABLE "app_menu" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"type" TEXT(2) NOT NULL, +"code" TEXT(20) NOT NULL, +"orderno" INTEGER, +"name" TEXT(100) NOT NULL, +"icon" TEXT(9000), +"islink" TEXT(2), +"url" TEXT(200), +"module_id" TEXT(40), +"parentid" TEXT(40), +"isdisplay" TEXT(2), +"lastmodifier" TEXT(40), +"lastmodifydate" TEXT, +"custom1" TEXT(100), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_module +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_module"; +CREATE TABLE "app_module" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"name" TEXT(200), +"pid" TEXT(40), +"level" INTEGER, +"node_type" TEXT(40), +"type" TEXT(40), +"canvas_style_data" TEXT, +"component_data" TEXT, +"status" INTEGER, +"self_watermark_status" INTEGER, +"sort" INTEGER, +"create_time" TEXT, +"create_by" TEXT(40), +"update_time" TEXT, +"update_by" TEXT(40), +"remark" TEXT(255), +"source" TEXT(255), +"delete_flag" INTEGER, +"delete_time" TEXT, +"delete_by" TEXT(40), +"version" INTEGER, +"content_id" TEXT(50), +"check_version" TEXT(50), +"custom1" TEXT(100), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_optlog +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_optlog"; +CREATE TABLE "app_optlog" ( +"id" TEXT(40) NOT NULL, +"usercode" TEXT(200), +"username" TEXT(200), +"opttype" TEXT(20), +"module" TEXT(200), +"description" TEXT(400), +"method" TEXT(200), +"params" TEXT, +"logtime" TEXT, +"requestip" TEXT(200), +"browser" TEXT(200), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_organization +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_organization"; +CREATE TABLE "app_organization" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"orgtype" TEXT(20), +"orgcode" TEXT(20), +"orgname" TEXT(200), +"parentid" TEXT(40), +"manager" TEXT(40), +"description" TEXT(1000), +"address" TEXT(100), +"contact_phone" TEXT(100), +"contact_person" TEXT(100), +"isvaild" TEXT(2) NOT NULL, +"lastmodifier" TEXT(40), +"lastmodifydate" TEXT, +"custom1" TEXT(100), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_role +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_role"; +CREATE TABLE "app_role" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"rolecode" TEXT(3) NOT NULL, +"rolename" TEXT(100) NOT NULL, +"type" TEXT(2) NOT NULL, +"description" TEXT(1000), +"isvaild" TEXT(2) NOT NULL, +"lastmodifier" TEXT(40) NOT NULL, +"lastmodifydate" TEXT NOT NULL, +"custom1" TEXT(100), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_role_menu"; +CREATE TABLE "app_role_menu" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"roleid" TEXT(40) NOT NULL, +"menuid" TEXT(40) NOT NULL, +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_role_users +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_role_users"; +CREATE TABLE "app_role_users" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"roleid" TEXT(40) NOT NULL, +"userid" TEXT(40) NOT NULL, +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Table structure for app_user +-- ---------------------------- +DROP TABLE IF EXISTS "main"."app_user"; +CREATE TABLE "app_user" ( +"id" TEXT(40) NOT NULL, +"app_id" TEXT(40), +"orgid" TEXT(40) NOT NULL, +"usertype" TEXT(20) NOT NULL, +"username" TEXT(100) NOT NULL, +"nickname" TEXT(255) NOT NULL, +"password" TEXT(200), +"email" TEXT(100), +"phone" TEXT(20), +"avatar" TEXT, +"status" TEXT(2), +"pwdvalidperiod" INTEGER, +"failednum" INTEGER, +"loginip" TEXT(40), +"failedlocktime" TEXT, +"pwdresettime" TEXT, +"lastmodifier" TEXT(40), +"lastmodifydate" TEXT, +"custom1" TEXT(100), +"custom2" TEXT(100), +"custom3" TEXT(100), +PRIMARY KEY ("id") +); + +-- ---------------------------- +-- Indexes structure for table app_optlog +-- ---------------------------- +CREATE INDEX "main"."inx_log_type" +ON "app_optlog" ("opttype" ASC); +CREATE INDEX "main"."log_create_time_index" +ON "app_optlog" ("logtime" ASC); diff --git a/backend/db/project.db b/backend/db/project.db new file mode 100644 index 0000000..6fdd66e Binary files /dev/null and b/backend/db/project.db differ diff --git a/backend/pom.xml b/backend/pom.xml new file mode 100644 index 0000000..28f11bc --- /dev/null +++ b/backend/pom.xml @@ -0,0 +1,141 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.0.0 + + + com.stdproject + stdproject-backend + 0.0.1-SNAPSHOT + stdproject-backend + Standard Project Backend + + 17 + 3.5.3 + 0.11.5 + 2.0.2 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-validation + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-aop + + + org.springframework.boot + spring-boot-starter-cache + + + javax.cache + cache-api + + + + + com.baomidou + mybatis-plus-boot-starter + ${mybatis-plus.version} + + + + mysql + mysql-connector-java + 8.0.30 + runtime + + + org.xerial + sqlite-jdbc + 3.36.0.3 + + + + io.jsonwebtoken + jjwt-api + ${jjwt.version} + + + io.jsonwebtoken + jjwt-impl + ${jjwt.version} + runtime + + + io.jsonwebtoken + jjwt-jackson + ${jjwt.version} + runtime + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${springdoc.version} + + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.security + spring-security-test + test + + + org.projectlombok + lombok + provided + + + com.baomidou + mybatis-plus-core + 3.5.3.1 + + + org.projectlombok + lombok + 1.18.34 provided + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/ProjectApplication.java b/backend/src/main/java/com/stdproject/ProjectApplication.java new file mode 100644 index 0000000..1ecc101 --- /dev/null +++ b/backend/src/main/java/com/stdproject/ProjectApplication.java @@ -0,0 +1,32 @@ +package com.stdproject; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * Spring Boot 应用启动类 + * + * @author StdProject + * @since 2023-12-07 + */ +@SpringBootApplication +@MapperScan("com.stdproject.mapper") +@EnableCaching +@EnableAsync +@EnableTransactionManagement +public class ProjectApplication { + + public static void main(String[] args) { + SpringApplication.run(ProjectApplication.class, args); + System.out.println("\n========================================"); + System.out.println(" StdProject 应用启动成功!"); + System.out.println(" 接口文档地址: http://localhost:8080/swagger-ui.html"); + System.out.println(" 应用端口: 8080"); + System.out.println("========================================\n"); + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/BusinessException.java b/backend/src/main/java/com/stdproject/common/BusinessException.java new file mode 100644 index 0000000..216b193 --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/BusinessException.java @@ -0,0 +1,106 @@ +package com.stdproject.common; + +/** + * 业务异常类 + * + * @author StdProject + */ +public class BusinessException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + /** + * 错误码 + */ + private Integer code; + + /** + * 错误消息 + */ + private String message; + + public BusinessException() { + super(); + } + + public BusinessException(String message) { + super(message); + this.message = message; + this.code = ResultCode.ERROR.getCode(); + } + + public BusinessException(Integer code, String message) { + super(message); + this.code = code; + this.message = message; + } + + public BusinessException(ResultCode resultCode) { + super(resultCode.getMessage()); + this.code = resultCode.getCode(); + this.message = resultCode.getMessage(); + } + + public BusinessException(String message, Throwable cause) { + super(message, cause); + this.message = message; + this.code = ResultCode.ERROR.getCode(); + } + + public BusinessException(Integer code, String message, Throwable cause) { + super(message, cause); + this.code = code; + this.message = message; + } + + public BusinessException(ResultCode resultCode, Throwable cause) { + super(resultCode.getMessage(), cause); + this.code = resultCode.getCode(); + this.message = resultCode.getMessage(); + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + @Override + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + /** + * 抛出业务异常 + * + * @param message 错误消息 + */ + public static void throwException(String message) { + throw new BusinessException(message); + } + + /** + * 抛出业务异常 + * + * @param code 错误码 + * @param message 错误消息 + */ + public static void throwException(Integer code, String message) { + throw new BusinessException(code, message); + } + + /** + * 抛出业务异常 + * + * @param resultCode 结果码枚举 + */ + public static void throwException(ResultCode resultCode) { + throw new BusinessException(resultCode); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/Constants.java b/backend/src/main/java/com/stdproject/common/Constants.java new file mode 100644 index 0000000..63b4221 --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/Constants.java @@ -0,0 +1,121 @@ +package com.stdproject.common; + +/** + * 系统常量类 + * + * @author StdProject + */ +public class Constants { + + /** + * JWT相关常量 + */ + public static final String JWT_HEADER = "Authorization"; + public static final String JWT_PREFIX = "Bearer "; + public static final String JWT_SECRET_KEY = "jwt.secret"; + public static final String JWT_EXPIRATION_KEY = "jwt.expiration"; + + /** + * 用户状态 + */ + public static final String USER_STATUS_NORMAL = "0"; // 正常 + public static final String USER_STATUS_DISABLED = "1"; // 停用 + public static final String USER_STATUS_LOCKED = "2"; // 锁定 + + /** + * 角色状态 + */ + public static final String ROLE_STATUS_NORMAL = "0"; // 正常 + public static final String ROLE_STATUS_DISABLED = "1"; // 停用 + + /** + * 菜单类型 + */ + public static final String MENU_TYPE_DIRECTORY = "M"; // 目录 + public static final String MENU_TYPE_MENU = "C"; // 菜单 + public static final String MENU_TYPE_BUTTON = "F"; // 按钮 + + /** + * 菜单状态 + */ + public static final String MENU_STATUS_NORMAL = "0"; // 正常 + public static final String MENU_STATUS_DISABLED = "1"; // 停用 + + /** + * 组织状态 + */ + public static final String ORG_STATUS_NORMAL = "0"; // 正常 + public static final String ORG_STATUS_DISABLED = "1"; // 停用 + + /** + * 操作类型 + */ + public static final String OPT_TYPE_LOGIN = "00"; // 登录 + public static final String OPT_TYPE_INSERT = "01"; // 新增 + public static final String OPT_TYPE_UPDATE = "02"; // 修改 + public static final String OPT_TYPE_DELETE = "03"; // 删除 + public static final String OPT_TYPE_QUERY = "06"; // 查询 + public static final String OPT_TYPE_OTHER = "09"; // 其他 + + /** + * 操作状态 + */ + public static final String OPT_STATUS_SUCCESS = "0"; // 成功 + public static final String OPT_STATUS_FAIL = "1"; // 失败 + + /** + * 数据权限类型 + */ + public static final String DATA_SCOPE_ALL = "1"; // 全部数据权限 + public static final String DATA_SCOPE_CUSTOM = "2"; // 自定义数据权限 + public static final String DATA_SCOPE_DEPT = "3"; // 部门数据权限 + public static final String DATA_SCOPE_DEPT_AND_CHILD = "4"; // 部门及以下数据权限 + public static final String DATA_SCOPE_SELF = "5"; // 仅本人数据权限 + + /** + * 字典状态 + */ + public static final String DICT_STATUS_NORMAL = "0"; // 正常 + public static final String DICT_STATUS_DISABLED = "1"; // 停用 + + /** + * 是否删除 + */ + public static final String DELETED_YES = "1"; // 已删除 + public static final String DELETED_NO = "0"; // 未删除 + + /** + * 性别 + */ + public static final String GENDER_MALE = "0"; // 男 + public static final String GENDER_FEMALE = "1"; // 女 + public static final String GENDER_UNKNOWN = "2"; // 未知 + + /** + * 默认密码 + */ + public static final String DEFAULT_PASSWORD = "123456"; + + /** + * 超级管理员角色编码 + */ + public static final String SUPER_ADMIN_ROLE = "admin"; + + /** + * 根节点ID + */ + public static final Long ROOT_NODE_ID = 0L; + + /** + * 缓存过期时间(秒) + */ + public static final int CACHE_EXPIRE_TIME = 3600; // 1小时 + public static final int CACHE_EXPIRE_TIME_SHORT = 300; // 5分钟 + public static final int CACHE_EXPIRE_TIME_LONG = 86400; // 24小时 + + /** + * 分页默认值 + */ + public static final int DEFAULT_PAGE_SIZE = 20; + public static final int MAX_PAGE_SIZE = 500; +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/DataPermission.java b/backend/src/main/java/com/stdproject/common/DataPermission.java new file mode 100644 index 0000000..7278902 --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/DataPermission.java @@ -0,0 +1,36 @@ +package com.stdproject.common; + +import java.lang.annotation.*; + +/** + * 数据权限注解 + * 用于标记需要进行数据权限控制的方法 + * + * @author StdProject + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DataPermission { + + /** + * 数据权限类型 + * 1-全部数据权限 2-自定义数据权限 3-部门数据权限 4-部门及以下数据权限 5-仅本人数据权限 + */ + String value() default "1"; + + /** + * 表别名 + */ + String tableAlias() default ""; + + /** + * 用户ID字段名 + */ + String userIdColumn() default "create_user"; + + /** + * 部门ID字段名 + */ + String deptIdColumn() default "dept_id"; +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/GlobalExceptionHandler.java b/backend/src/main/java/com/stdproject/common/GlobalExceptionHandler.java new file mode 100644 index 0000000..e031221 --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/GlobalExceptionHandler.java @@ -0,0 +1,188 @@ +package com.stdproject.common; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.core.AuthenticationException; +import org.springframework.validation.BindException; +import org.springframework.validation.FieldError; +import org.springframework.web.HttpRequestMethodNotSupportedException; +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.method.annotation.MethodArgumentTypeMismatchException; +import org.springframework.web.servlet.NoHandlerFoundException; + + +import java.sql.SQLException; +import java.util.Set; + +/** + * 全局异常处理器 + * + * @author StdProject + */ +@Slf4j +@RestControllerAdvice +public class GlobalExceptionHandler { + + /** + * 处理业务异常 + */ + @ExceptionHandler(BusinessException.class) + @ResponseStatus(HttpStatus.OK) + public Result handleBusinessException(BusinessException e, HttpServletRequest request) { + log.warn("业务异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.error(e.getCode(), e.getMessage()); + } + + /** + * 处理参数校验异常 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) { + log.warn("参数校验异常: {} - {}", request.getRequestURI(), e.getMessage()); + StringBuilder message = new StringBuilder(); + for (FieldError error : e.getBindingResult().getFieldErrors()) { + message.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("; "); + } + return Result.badRequest(message.toString()); + } + + /** + * 处理参数绑定异常 + */ + @ExceptionHandler(BindException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleBindException(BindException e, HttpServletRequest request) { + log.warn("参数绑定异常: {} - {}", request.getRequestURI(), e.getMessage()); + StringBuilder message = new StringBuilder(); + for (FieldError error : e.getBindingResult().getFieldErrors()) { + message.append(error.getField()).append(": ").append(error.getDefaultMessage()).append("; "); + } + return Result.badRequest(message.toString()); + } + + /** + * 处理约束违反异常 + */ + @ExceptionHandler(ConstraintViolationException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) { + log.warn("约束违反异常: {} - {}", request.getRequestURI(), e.getMessage()); + StringBuilder message = new StringBuilder(); + Set> violations = e.getConstraintViolations(); + for (ConstraintViolation violation : violations) { + message.append(violation.getPropertyPath()).append(": ").append(violation.getMessage()).append("; "); + } + return Result.badRequest(message.toString()); + } + + /** + * 处理参数类型不匹配异常 + */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) { + log.warn("参数类型不匹配异常: {} - {}", request.getRequestURI(), e.getMessage()); + String message = String.format("参数 '%s' 的值 '%s' 类型不正确", e.getName(), e.getValue()); + return Result.badRequest(message); + } + + /** + * 处理认证异常 + */ + @ExceptionHandler(AuthenticationException.class) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public Result handleAuthenticationException(AuthenticationException e, HttpServletRequest request) { + log.warn("认证异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.unauthorized(); + } + + /** + * 处理凭证错误异常 + */ + @ExceptionHandler(BadCredentialsException.class) + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public Result handleBadCredentialsException(BadCredentialsException e, HttpServletRequest request) { + log.warn("凭证错误异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.error(ResultCode.LOGIN_ERROR); + } + + /** + * 处理访问拒绝异常 + */ + @ExceptionHandler(AccessDeniedException.class) + @ResponseStatus(HttpStatus.FORBIDDEN) + public Result handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) { + log.warn("访问拒绝异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.forbidden(); + } + + /** + * 处理请求方法不支持异常 + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) + public Result handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e, HttpServletRequest request) { + log.warn("请求方法不支持异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.error(ResultCode.METHOD_NOT_ALLOWED); + } + + /** + * 处理资源未找到异常 + */ + @ExceptionHandler(NoHandlerFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public Result handleNoHandlerFoundException(NoHandlerFoundException e, HttpServletRequest request) { + log.warn("资源未找到异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.notFound(); + } + + /** + * 处理数据完整性违反异常 + */ + @ExceptionHandler(DataIntegrityViolationException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + public Result handleDataIntegrityViolationException(DataIntegrityViolationException e, HttpServletRequest request) { + log.warn("数据完整性违反异常: {} - {}", request.getRequestURI(), e.getMessage()); + return Result.error(ResultCode.DATA_INTEGRITY_VIOLATION); + } + + /** + * 处理SQL异常 + */ + @ExceptionHandler(SQLException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleSQLException(SQLException e, HttpServletRequest request) { + log.error("SQL异常: {} - {}", request.getRequestURI(), e.getMessage(), e); + return Result.error(ResultCode.DATABASE_ERROR); + } + + /** + * 处理运行时异常 + */ + @ExceptionHandler(RuntimeException.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleRuntimeException(RuntimeException e, HttpServletRequest request) { + log.error("运行时异常: {} - {}", request.getRequestURI(), e.getMessage(), e); + return Result.error(ResultCode.ERROR.getCode(), e.getMessage()); + } + + /** + * 处理其他异常 + */ + @ExceptionHandler(Exception.class) + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public Result handleException(Exception e, HttpServletRequest request) { + log.error("系统异常: {} - {}", request.getRequestURI(), e.getMessage(), e); + return Result.error(ResultCode.UNKNOWN_ERROR); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/OperationLog.java b/backend/src/main/java/com/stdproject/common/OperationLog.java new file mode 100644 index 0000000..150d4bf --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/OperationLog.java @@ -0,0 +1,41 @@ +package com.stdproject.common; + +import java.lang.annotation.*; + +/** + * 操作日志注解 + * 用于标记需要记录操作日志的方法 + * + * @author StdProject + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface OperationLog { + + /** + * 操作类型 + * 00-登录 01-新增 02-修改 03-删除 06-查询 09-其他 + */ + String type() default "09"; + + /** + * 模块名称 + */ + String module() default ""; + + /** + * 操作描述 + */ + String description() default ""; + + /** + * 是否记录请求参数 + */ + boolean recordParams() default true; + + /** + * 是否记录返回结果 + */ + boolean recordResult() default false; +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/OperationLogAspect.java b/backend/src/main/java/com/stdproject/common/OperationLogAspect.java new file mode 100644 index 0000000..ee8485e --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/OperationLogAspect.java @@ -0,0 +1,172 @@ +package com.stdproject.common; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.stdproject.entity.AppOptLog; +import com.stdproject.service.IAppOptLogService; +import com.stdproject.utils.JwtUtils; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + + +import java.lang.reflect.Method; +import java.time.LocalDateTime; +import java.util.Arrays; + +/** + * 操作日志切面 + * + * @author StdProject + */ +@Aspect +@Component +@Slf4j +public class OperationLogAspect { + + @Autowired + private IAppOptLogService appOptLogService; + + @Autowired + private JwtUtils jwtUtils; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + /** + * 定义切点 + */ + @Pointcut("@annotation(com.stdproject.common.OperationLog)") + public void operationLogPointcut() { + } + + /** + * 正常返回通知 + */ + @AfterReturning(pointcut = "operationLogPointcut()", returning = "result") + public void doAfterReturning(JoinPoint joinPoint, Object result) { + handleLog(joinPoint, null, result); + } + + /** + * 异常通知 + */ + @AfterThrowing(pointcut = "operationLogPointcut()", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, Exception e) { + handleLog(joinPoint, e, null); + } + + /** + * 处理日志记录 + */ + private void handleLog(JoinPoint joinPoint, Exception e, Object result) { + try { + // 获取注解信息 + OperationLog operationLog = getAnnotationLog(joinPoint); + if (operationLog == null) { + return; + } + + // 获取请求信息 + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (attributes == null) { + return; + } + HttpServletRequest request = attributes.getRequest(); + + // 创建操作日志对象 + AppOptLog optLog = new AppOptLog(); + + // 设置基本信息 + optLog.setOpttype(operationLog.type()); + optLog.setModule(operationLog.module()); + optLog.setDescription(operationLog.description()); + optLog.setMethod(request.getMethod() + " " + request.getRequestURI()); + optLog.setRequestip(getIpAddress(request)); + optLog.setBrowser(request.getHeader("User-Agent")); + optLog.setLogtime(LocalDateTime.now()); + + // 设置操作用户 + String token = request.getHeader("Authorization"); + if (token != null && token.startsWith("Bearer ")) { + token = token.substring(7); + try { + String username = jwtUtils.getUsernameFromToken(token); + optLog.setUsername(username); + } catch (Exception ex) { + log.warn("解析JWT token失败: {}", ex.getMessage()); + } + } + + // 设置请求参数 + if (operationLog.recordParams()) { + String methodParams = getMethodParams(joinPoint); + optLog.setParams(methodParams); + } + + // 保存日志 + appOptLogService.save(optLog); + + } catch (Exception ex) { + log.error("记录操作日志异常: {}", ex.getMessage(), ex); + } + } + + /** + * 获取注解信息 + */ + private OperationLog getAnnotationLog(JoinPoint joinPoint) { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + return method.getAnnotation(OperationLog.class); + } + + /** + * 获取方法参数 + */ + private String getMethodParams(JoinPoint joinPoint) { + try { + Object[] args = joinPoint.getArgs(); + if (args == null || args.length == 0) { + return ""; + } + String params = objectMapper.writeValueAsString(Arrays.asList(args)); + if (params.length() > 2000) { + params = params.substring(0, 2000) + "..."; + } + return params; + } catch (Exception e) { + return "参数序列化失败"; + } + } + + /** + * 获取客户端IP地址 + */ + private String getIpAddress(HttpServletRequest request) { + String ip = request.getHeader("X-Forwarded-For"); + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + return ip; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/PageRequest.java b/backend/src/main/java/com/stdproject/common/PageRequest.java new file mode 100644 index 0000000..8495a86 --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/PageRequest.java @@ -0,0 +1,72 @@ +package com.stdproject.common; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + + + +/** + * 分页查询请求类 + * + * @author StdProject + */ +@Data +public class PageRequest { + + /** + * 当前页码,从1开始 + */ + @NotNull(message = "页码不能为空") + @Min(value = 1, message = "页码必须大于0") @Min(value = 1, message = "页码必须大于0") + private Integer current = 1; + + /** + * 每页大小 + */ + @NotNull(message = "每页大小不能为空") + @Min(value = 1, message = "每页大小必须大于0") + private Integer size = 20; + + /** + * 排序字段 + */ + private String orderBy; + + /** + * 排序方向:asc-升序,desc-降序 + */ + private String orderDirection = "desc"; + + /** + * 搜索关键字 + */ + private String keyword; + + /** + * 获取偏移量 + * + * @return 偏移量 + */ + public Integer getOffset() { + return (current - 1) * size; + } + + /** + * 是否升序排序 + * + * @return 是否升序 + */ + public boolean isAsc() { + return "asc".equalsIgnoreCase(orderDirection); + } + + /** + * 是否降序排序 + * + * @return 是否降序 + */ + public boolean isDesc() { + return "desc".equalsIgnoreCase(orderDirection); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/Result.java b/backend/src/main/java/com/stdproject/common/Result.java new file mode 100644 index 0000000..3861e5e --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/Result.java @@ -0,0 +1,191 @@ +package com.stdproject.common; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Data; + +import java.io.Serializable; + +/** + * 统一响应结果类 + * + * @author StdProject + * @param 数据类型 + */ +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Result implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 响应码 + */ + private Integer code; + + /** + * 响应消息 + */ + private String message; + + /** + * 响应数据 + */ + private T data; + + /** + * 时间戳 + */ + private Long timestamp; + + public Result() { + this.timestamp = System.currentTimeMillis(); + } + + public Result(Integer code, String message) { + this(); + this.code = code; + this.message = message; + } + + public Result(Integer code, String message, T data) { + this(code, message); + this.data = data; + } + + /** + * 成功响应 + * + * @param 数据类型 + * @return 成功响应 + */ + public static Result success() { + return new Result<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage()); + } + + /** + * 成功响应 + * + * @param data 响应数据 + * @param 数据类型 + * @return 成功响应 + */ + public static Result success(T data) { + return new Result<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data); + } + + /** + * 成功响应 + * + * @param message 响应消息 + * @param data 响应数据 + * @param 数据类型 + * @return 成功响应 + */ + public static Result success(String message, T data) { + return new Result<>(ResultCode.SUCCESS.getCode(), message, data); + } + + /** + * 失败响应 + * + * @param 数据类型 + * @return 失败响应 + */ + public static Result error() { + return new Result<>(ResultCode.ERROR.getCode(), ResultCode.ERROR.getMessage()); + } + + /** + * 失败响应 + * + * @param message 错误消息 + * @param 数据类型 + * @return 失败响应 + */ + public static Result error(String message) { + return new Result<>(ResultCode.ERROR.getCode(), message); + } + + /** + * 失败响应 + * + * @param code 错误码 + * @param message 错误消息 + * @param 数据类型 + * @return 失败响应 + */ + public static Result error(Integer code, String message) { + return new Result<>(code, message); + } + + /** + * 失败响应 + * + * @param resultCode 结果码枚举 + * @param 数据类型 + * @return 失败响应 + */ + public static Result error(ResultCode resultCode) { + return new Result<>(resultCode.getCode(), resultCode.getMessage()); + } + + /** + * 未授权响应 + * + * @param 数据类型 + * @return 未授权响应 + */ + public static Result unauthorized() { + return new Result<>(ResultCode.UNAUTHORIZED.getCode(), ResultCode.UNAUTHORIZED.getMessage()); + } + + /** + * 禁止访问响应 + * + * @param 数据类型 + * @return 禁止访问响应 + */ + public static Result forbidden() { + return new Result<>(ResultCode.FORBIDDEN.getCode(), ResultCode.FORBIDDEN.getMessage()); + } + + /** + * 资源未找到响应 + * + * @param 数据类型 + * @return 资源未找到响应 + */ + public static Result notFound() { + return new Result<>(ResultCode.NOT_FOUND.getCode(), ResultCode.NOT_FOUND.getMessage()); + } + + /** + * 参数错误响应 + * + * @param 数据类型 + * @return 参数错误响应 + */ + public static Result badRequest() { + return new Result<>(ResultCode.BAD_REQUEST.getCode(), ResultCode.BAD_REQUEST.getMessage()); + } + + /** + * 参数错误响应 + * + * @param message 错误消息 + * @param 数据类型 + * @return 参数错误响应 + */ + public static Result badRequest(String message) { + return new Result<>(ResultCode.BAD_REQUEST.getCode(), message); + } + + /** + * 判断是否成功 + * + * @return 是否成功 + */ + public boolean isSuccess() { + return ResultCode.SUCCESS.getCode().equals(this.code); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/common/ResultCode.java b/backend/src/main/java/com/stdproject/common/ResultCode.java new file mode 100644 index 0000000..f985514 --- /dev/null +++ b/backend/src/main/java/com/stdproject/common/ResultCode.java @@ -0,0 +1,223 @@ +package com.stdproject.common; + +/** + * 结果码枚举 + * + * @author StdProject + */ +public enum ResultCode { + + /** + * 成功 + */ + SUCCESS(200, "操作成功"), + + /** + * 失败 + */ + ERROR(500, "操作失败"), + + /** + * 参数错误 + */ + BAD_REQUEST(400, "参数错误"), + + /** + * 未授权 + */ + UNAUTHORIZED(401, "未授权"), + + /** + * 禁止访问 + */ + FORBIDDEN(403, "禁止访问"), + + /** + * 资源未找到 + */ + NOT_FOUND(404, "资源未找到"), + + /** + * 方法不允许 + */ + METHOD_NOT_ALLOWED(405, "方法不允许"), + + /** + * 请求超时 + */ + REQUEST_TIMEOUT(408, "请求超时"), + + /** + * 用户名或密码错误 + */ + LOGIN_ERROR(1001, "用户名或密码错误"), + + /** + * 用户已被禁用 + */ + USER_DISABLED(1002, "用户已被禁用"), + + /** + * 用户已被锁定 + */ + USER_LOCKED(1003, "用户已被锁定"), + + /** + * 密码已过期 + */ + PASSWORD_EXPIRED(1004, "密码已过期"), + + /** + * 登录失败次数过多 + */ + LOGIN_FAILED_TOO_MANY(1005, "登录失败次数过多,账户已被锁定"), + + /** + * Token无效 + */ + TOKEN_INVALID(1006, "Token无效"), + + /** + * Token已过期 + */ + TOKEN_EXPIRED(1007, "Token已过期"), + + /** + * 用户不存在 + */ + USER_NOT_FOUND(1008, "用户不存在"), + + /** + * 用户名已存在 + */ + USERNAME_EXISTS(1009, "用户名已存在"), + + /** + * 邮箱已存在 + */ + EMAIL_EXISTS(1010, "邮箱已存在"), + + /** + * 手机号已存在 + */ + PHONE_EXISTS(1011, "手机号已存在"), + + /** + * 角色不存在 + */ + ROLE_NOT_FOUND(1012, "角色不存在"), + + /** + * 角色已存在 + */ + ROLE_EXISTS(1013, "角色已存在"), + + /** + * 菜单不存在 + */ + MENU_NOT_FOUND(1014, "菜单不存在"), + + /** + * 菜单已存在 + */ + MENU_EXISTS(1015, "菜单已存在"), + + /** + * 组织不存在 + */ + ORGANIZATION_NOT_FOUND(1016, "组织不存在"), + + /** + * 组织已存在 + */ + ORGANIZATION_EXISTS(1017, "组织已存在"), + + /** + * 数据字典不存在 + */ + DICTIONARY_NOT_FOUND(1018, "数据字典不存在"), + + /** + * 数据字典已存在 + */ + DICTIONARY_EXISTS(1019, "数据字典已存在"), + + /** + * 文件上传失败 + */ + FILE_UPLOAD_ERROR(2001, "文件上传失败"), + + /** + * 文件下载失败 + */ + FILE_DOWNLOAD_ERROR(2002, "文件下载失败"), + + /** + * 文件不存在 + */ + FILE_NOT_FOUND(2003, "文件不存在"), + + /** + * 文件格式不支持 + */ + FILE_FORMAT_NOT_SUPPORTED(2004, "文件格式不支持"), + + /** + * 文件大小超出限制 + */ + FILE_SIZE_EXCEEDED(2005, "文件大小超出限制"), + + /** + * 数据库操作失败 + */ + DATABASE_ERROR(3001, "数据库操作失败"), + + /** + * 数据不存在 + */ + DATA_NOT_FOUND(3002, "数据不存在"), + + /** + * 数据已存在 + */ + DATA_EXISTS(3003, "数据已存在"), + + /** + * 数据完整性约束违反 + */ + DATA_INTEGRITY_VIOLATION(3004, "数据完整性约束违反"), + + /** + * 系统繁忙 + */ + SYSTEM_BUSY(9001, "系统繁忙,请稍后重试"), + + /** + * 系统维护中 + */ + SYSTEM_MAINTENANCE(9002, "系统维护中"), + /** + * 系统维护中 + */ + + /** + * 未知错误 + */ + UNKNOWN_ERROR(9999, "未知错误"); + + private final Integer code; + private final String message; + + ResultCode(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public String getMessage() { + return message; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/CacheConfig.java b/backend/src/main/java/com/stdproject/config/CacheConfig.java new file mode 100644 index 0000000..3d4f348 --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/CacheConfig.java @@ -0,0 +1,26 @@ +package com.stdproject.config; + +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Configuration; + +/** + * 缓存配置类 + * + * @author StdProject + */ +@Configuration +@EnableCaching +public class CacheConfig { + + // 缓存配置主要通过application.yml中的spring.cache.jcache.config配置 + // 这里启用缓存注解支持 + + /** + * 缓存名称常量 + */ + public static final String USER_CACHE = "userCache"; + public static final String ROLE_CACHE = "roleCache"; + public static final String MENU_CACHE = "menuCache"; + public static final String ORGANIZATION_CACHE = "organizationCache"; + public static final String DICTIONARY_CACHE = "dictionaryCache"; +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/CustomUserDetailsService.java b/backend/src/main/java/com/stdproject/config/CustomUserDetailsService.java new file mode 100644 index 0000000..e02184b --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/CustomUserDetailsService.java @@ -0,0 +1,210 @@ +package com.stdproject.config; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.stdproject.entity.AppUser; +import com.stdproject.entity.AppRole; +import com.stdproject.entity.AppRoleUser; +import com.stdproject.entity.AppRoleMenu; +import com.stdproject.entity.AppMenu; +import com.stdproject.service.IAppUserService; +import com.stdproject.service.IAppRoleService; +import com.stdproject.service.IAppRoleUserService; +import com.stdproject.service.IAppRoleMenuService; +import com.stdproject.service.IAppMenuService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.HashSet; +import java.util.stream.Collectors; + +/** + * 自定义用户详情服务 + * 实现Spring Security的UserDetailsService接口 + * + * @author StdProject + */ +@Slf4j +@Service +public class CustomUserDetailsService implements UserDetailsService { + + @Autowired + private IAppUserService appUserService; + + @Autowired + private IAppRoleService appRoleService; + + @Autowired + private IAppRoleUserService appRoleUserService; + + @Autowired + private IAppRoleMenuService appRoleMenuService; + + @Autowired + private IAppMenuService appMenuService; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + log.debug("加载用户信息: {}", username); + + AppUser appUser = appUserService.findByUsername(username); + if (appUser == null) { + log.warn("用户不存在: {}", username); + throw new UsernameNotFoundException("用户不存在: " + username); + } + + // 检查用户状态 + if (!"1".equals(appUser.getStatus())) { + log.warn("用户已被禁用: {}", username); + throw new UsernameNotFoundException("用户已被禁用: " + username); + } + + // 构建用户权限 + Collection authorities = buildUserAuthorities(appUser); + + return User.builder() + .username(appUser.getUsername()) + .password(appUser.getPassword()) + .authorities(authorities) + .accountExpired(false) + .accountLocked(isAccountLocked(appUser)) + .credentialsExpired(isCredentialsExpired(appUser)) + .disabled(!"1".equals(appUser.getStatus())) + .build(); + } + + /** + * 构建用户权限 + * + * @param appUser 用户信息 + * @return 权限集合 + */ + private Collection buildUserAuthorities(AppUser appUser) { + Set authorities = new HashSet<>(); + + try { + // 根据用户类型添加基本角色权限 + if ("0".equals(appUser.getUsertype())) { + authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); + } else { + authorities.add(new SimpleGrantedAuthority("ROLE_USER")); + } + + // 查询用户的角色 + QueryWrapper roleUserQuery = new QueryWrapper<>(); + roleUserQuery.eq("userid", appUser.getId()); + List roleUsers = appRoleUserService.list(roleUserQuery); + + if (!roleUsers.isEmpty()) { + // 获取角色ID列表 + List roleIds = roleUsers.stream() + .map(AppRoleUser::getRoleid) + .collect(Collectors.toList()); + + // 查询角色信息并添加角色权限 + List roles = appRoleService.listByIds(roleIds); + for (AppRole role : roles) { + if ("1".equals(role.getIsvaild())) { + // 添加角色权限,格式:ROLE_角色编码 + if (StringUtils.hasText(role.getRolecode())) { + authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRolecode().toUpperCase())); + } + } + } + + // 查询角色关联的菜单权限 + QueryWrapper roleMenuQuery = new QueryWrapper<>(); + roleMenuQuery.in("roleid", roleIds); + List roleMenus = appRoleMenuService.list(roleMenuQuery); + + if (!roleMenus.isEmpty()) { + // 获取菜单ID列表 + List menuIds = roleMenus.stream() + .map(AppRoleMenu::getMenuid) + .distinct() + .collect(Collectors.toList()); + + // 查询菜单信息并添加菜单权限 + List menus = appMenuService.listByIds(menuIds); + for (AppMenu menu : menus) { + if ("1".equals(menu.getIsdisplay()) && StringUtils.hasText(menu.getCode())) { + // 添加菜单权限,格式:菜单编码 + authorities.add(new SimpleGrantedAuthority(menu.getCode())); + + // 根据菜单类型添加操作权限 + String menuCode = menu.getCode(); + if (StringUtils.hasText(menuCode)) { + // 为每个菜单添加基本操作权限 + authorities.add(new SimpleGrantedAuthority(menuCode + ":list")); + authorities.add(new SimpleGrantedAuthority(menuCode + ":detail")); + + // 管理员拥有所有操作权限 + if ("0".equals(appUser.getUsertype())) { + authorities.add(new SimpleGrantedAuthority(menuCode + ":add")); + authorities.add(new SimpleGrantedAuthority(menuCode + ":edit")); + authorities.add(new SimpleGrantedAuthority(menuCode + ":delete")); + authorities.add(new SimpleGrantedAuthority(menuCode + ":permission")); + } + } + } + } + } + } + + log.debug("用户 {} 的权限列表: {}", appUser.getUsername(), + authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList())); + + } catch (Exception e) { + log.error("构建用户权限失败: {}", e.getMessage(), e); + // 发生异常时,至少保证基本角色权限 + authorities.clear(); + if ("0".equals(appUser.getUsertype())) { + authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); + } else { + authorities.add(new SimpleGrantedAuthority("ROLE_USER")); + } + } + + return authorities; + } + + /** + * 检查账户是否被锁定 + * + * @param appUser 用户信息 + * @return 是否被锁定 + */ + private boolean isAccountLocked(AppUser appUser) { + // 检查登录失败锁定时间 + if (appUser.getFailedlocktime() != null) { + // 如果锁定时间还未过期,则账户被锁定 + return appUser.getFailedlocktime().isAfter(java.time.LocalDateTime.now()); + } + return false; + } + + /** + * 检查凭证是否过期 + * + * @param appUser 用户信息 + * @return 是否过期 + */ + private boolean isCredentialsExpired(AppUser appUser) { + // 检查密码是否过期 + if (appUser.getPwdresettime() != null && appUser.getPwdvalidperiod() != null) { + java.time.LocalDateTime expireTime = appUser.getPwdresettime().plusDays(appUser.getPwdvalidperiod()); + return expireTime.isBefore(java.time.LocalDateTime.now()); + } + return false; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/JwtAuthenticationEntryPoint.java b/backend/src/main/java/com/stdproject/config/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..1688df9 --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/JwtAuthenticationEntryPoint.java @@ -0,0 +1,43 @@ +package com.stdproject.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.stdproject.common.Result; +import com.stdproject.common.ResultCode; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + + +import java.io.IOException; + +/** + * JWT认证入口点 + * 处理未认证的请求 + * + * @author StdProject + */ +@Slf4j +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) + throws IOException, ServletException { + + log.warn("未认证访问: {} - {}", request.getRequestURI(), authException.getMessage()); + + response.setContentType("application/json;charset=UTF-8"); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + + Result result = Result.error(ResultCode.UNAUTHORIZED); + + ObjectMapper objectMapper = new ObjectMapper(); + String jsonResult = objectMapper.writeValueAsString(result); + + response.getWriter().write(jsonResult); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/JwtAuthenticationFilter.java b/backend/src/main/java/com/stdproject/config/JwtAuthenticationFilter.java new file mode 100644 index 0000000..a077d7e --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/JwtAuthenticationFilter.java @@ -0,0 +1,78 @@ +package com.stdproject.config; + +import com.stdproject.utils.JwtUtils; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.OncePerRequestFilter; + + +import java.io.IOException; + +/** + * JWT认证过滤器 + * + * @author StdProject + */ +@Slf4j +@Component +public class JwtAuthenticationFilter extends OncePerRequestFilter { + + @Autowired + private JwtUtils jwtUtils; + + @Autowired + private UserDetailsService userDetailsService; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + try { + String jwt = getJwtFromRequest(request); + + if (StringUtils.hasText(jwt) && SecurityContextHolder.getContext().getAuthentication() == null) { + String username = jwtUtils.getUsernameFromToken(jwt); + + if (StringUtils.hasText(username)) { + UserDetails userDetails = userDetailsService.loadUserByUsername(username); + + if (jwtUtils.validateToken(jwt, userDetails.getUsername())) { + UsernamePasswordAuthenticationToken authentication = + new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + } + } + } + } catch (Exception e) { + log.error("无法设置用户认证: {}", e.getMessage()); + } + + filterChain.doFilter(request, response); + } + + /** + * 从请求中获取JWT令牌 + * + * @param request HTTP请求 + * @return JWT令牌 + */ + private String getJwtFromRequest(HttpServletRequest request) { + String bearerToken = request.getHeader("Authorization"); + if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { + return bearerToken.substring(7); + } + return null; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/MybatisPlusConfig.java b/backend/src/main/java/com/stdproject/config/MybatisPlusConfig.java new file mode 100644 index 0000000..5096d9d --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/MybatisPlusConfig.java @@ -0,0 +1,40 @@ +package com.stdproject.config; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * MyBatis-Plus配置类 + * + * @author StdProject + */ +@Configuration +@MapperScan("com.stdproject.mapper") +public class MybatisPlusConfig { + + /** + * MyBatis-Plus拦截器配置 + */ + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + + // 分页插件 + PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); + // 设置最大单页限制数量,默认 500 条,-1 不受限制 + paginationInnerInterceptor.setMaxLimit(1000L); + // 溢出总页数后是否进行处理 + paginationInnerInterceptor.setOverflow(false); + interceptor.addInnerInterceptor(paginationInnerInterceptor); + + // 乐观锁插件 + interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); + + return interceptor; + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/PasswordEncoderConfig.java b/backend/src/main/java/com/stdproject/config/PasswordEncoderConfig.java new file mode 100644 index 0000000..1683e2d --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/PasswordEncoderConfig.java @@ -0,0 +1,21 @@ +package com.stdproject.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * 密码编码器配置类 + * + * @author StdProject + */ +@Configuration +public class PasswordEncoderConfig { + + @Bean + public PasswordEncoder passwordEncoder() { + + return new BCryptPasswordEncoder(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/SecurityConfig.java b/backend/src/main/java/com/stdproject/config/SecurityConfig.java new file mode 100644 index 0000000..1f6dc64 --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/SecurityConfig.java @@ -0,0 +1,172 @@ +package com.stdproject.config; + +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +import java.util.Arrays; +import java.util.List; + +/** + * Spring Security配置类 + * + * @author StdProject + */ +@Configuration +@EnableWebSecurity +@EnableMethodSecurity(prePostEnabled = true) +@RequiredArgsConstructor +public class SecurityConfig { + + @Autowired + private PasswordEncoder passwordEncoder; + + private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + private final JwtAuthenticationFilter jwtAuthenticationFilter; + private final CustomUserDetailsService customUserDetailsService; + + @Value("${spring.security.jwt.enabled:true}") + private boolean jwtEnabled; + + @Value("${spring.security.cors.allowed-origins:http://localhost:3000,http://localhost:8080}") + private List allowedOrigins; + + @Value("${spring.security.cors.max-age:3600}") + private Long corsMaxAge; + + // 公开路径配置 + private static final String[] PUBLIC_PATHS = { + "/api/auth/**", + "/api/public/**", + "/swagger-ui/**", + "/v3/api-docs/**", + "/swagger-ui.html", + "/webjars/**", + "/favicon.ico", + "/error", + "/actuator/health", + "/actuator/info" + }; + + + /** + * 认证管理器 + */ + @Bean + public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception { + return config.getAuthenticationManager(); + } + + /** + * CORS配置 + * 更安全的CORS配置,支持配置化的允许源 + */ + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + + // 设置允许的源,支持配置化 + configuration.setAllowedOrigins(allowedOrigins); + + // 设置允许的HTTP方法 + configuration.setAllowedMethods(Arrays.asList( + "GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH" + )); + + // 设置允许的请求头 + configuration.setAllowedHeaders(Arrays.asList( + "Authorization", "Content-Type", "X-Requested-With", + "Accept", "Origin", "Access-Control-Request-Method", + "Access-Control-Request-Headers", "X-CSRF-TOKEN" + )); + + // 设置暴露的响应头 + configuration.setExposedHeaders(Arrays.asList( + "Access-Control-Allow-Origin", "Access-Control-Allow-Credentials", + "Authorization", "Content-Disposition" + )); + + configuration.setAllowCredentials(true); + configuration.setMaxAge(corsMaxAge); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } + + /** + * 安全过滤器链配置 + * 增强的安全配置,包含安全头和更完善的认证授权 + */ + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + // CORS配置 + .cors(cors -> cors.configurationSource(corsConfigurationSource())) + + // 禁用CSRF(因为使用JWT,无状态) + .csrf(csrf -> csrf.disable()) + + // 会话管理配置 + .sessionManagement(session -> session + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .maximumSessions(1) + .maxSessionsPreventsLogin(false) + ) + + // 异常处理配置 + .exceptionHandling(ex -> ex + .authenticationEntryPoint(jwtAuthenticationEntryPoint) + ) + + // 安全头配置 + .headers(headers -> headers + // 禁用iframe嵌入,防止点击劫持攻击 + .frameOptions().deny() + // 设置X-Content-Type-Options头为nosniff,防止MIME类型嗅探攻击 + .contentTypeOptions().and() + // 设置Referrer Policy为strict-origin-when-cross-origin + // 跨域请求时只发送源(origin),同源请求发送完整referrer + .referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN) + // 注意:已移除HSTS配置,不再强制使用HTTPS + ); + + // 根据配置决定是否启用JWT认证 + if (jwtEnabled) { + http.authorizeHttpRequests(authz -> authz + // 公开接口,无需认证 + .requestMatchers(PUBLIC_PATHS).permitAll() + // 管理员接口需要管理员权限 + .requestMatchers("/api/admin/**").hasRole("ADMIN") + // 其他所有请求都需要认证 + .anyRequest().authenticated() + ); + + // 添加JWT过滤器 + http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); + } else { + // 如果禁用JWT认证,则允许所有请求(开发环境) + http.authorizeHttpRequests(authz -> authz + .anyRequest().permitAll() + ); + } + + return http.build(); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/SwaggerConfig.java b/backend/src/main/java/com/stdproject/config/SwaggerConfig.java new file mode 100644 index 0000000..88437e3 --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/SwaggerConfig.java @@ -0,0 +1,46 @@ +package com.stdproject.config; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Swagger配置类 + * + * @author StdProject + */ +@Configuration +public class SwaggerConfig { + + /** + * OpenAPI配置 + */ + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .info(new Info() + .title("StdProject API") + .version("1.0.0") + .description("标准项目后端API文档") + .contact(new Contact() + .name("StdProject Team") + .email("support@stdproject.com") + .url("https://www.stdproject.com")) + .license(new License() + .name("Apache 2.0") + .url("https://www.apache.org/licenses/LICENSE-2.0"))) + .components(new Components() + .addSecuritySchemes("Bearer", new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + .description("JWT认证,请在值前面加上'Bearer '前缀"))) + .addSecurityItem(new SecurityRequirement().addList("Bearer")); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/config/WebConfig.java b/backend/src/main/java/com/stdproject/config/WebConfig.java new file mode 100644 index 0000000..e207fd0 --- /dev/null +++ b/backend/src/main/java/com/stdproject/config/WebConfig.java @@ -0,0 +1,28 @@ +package com.stdproject.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * Web配置类 + * + * @author StdProject + */ +@Configuration +public class WebConfig implements WebMvcConfigurer { + + /** + * 静态资源处理 + */ + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + // Swagger UI 静态资源 + registry.addResourceHandler("/swagger-ui/**") + .addResourceLocations("classpath:/META-INF/resources/webjars/swagger-ui/"); + + // 其他静态资源 + registry.addResourceHandler("/static/**") + .addResourceLocations("classpath:/static/"); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AppDictionaryController.java b/backend/src/main/java/com/stdproject/controller/AppDictionaryController.java new file mode 100644 index 0000000..bbce2a5 --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AppDictionaryController.java @@ -0,0 +1,270 @@ +package com.stdproject.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.stdproject.common.OperationLog; +import com.stdproject.common.PageRequest; +import com.stdproject.common.Result; +import com.stdproject.entity.AppDictionary; +import com.stdproject.service.IAppDictionaryService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 应用-数据字典表 前端控制器 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Tag(name = "数据字典管理", description = "数据字典添加、数据字典修改、数据字典删除、数据字典查询等功能") +@RestController +@RequestMapping("/app-dictionary") +public class AppDictionaryController { + + @Autowired + private IAppDictionaryService appDictionaryService; + + @Operation(summary = "分页查询数据字典列表") + @PostMapping("/page") + @OperationLog(type = "06", module = "数据字典管理", description = "分页查询数据字典列表") + public Result> page(@RequestBody @Valid PageRequest pageRequest) { + Page page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 关键字搜索 + if (StringUtils.hasText(pageRequest.getKeyword())) { + queryWrapper.and(wrapper -> wrapper + .like("dictname", pageRequest.getKeyword()) + .or().like("dictcode", pageRequest.getKeyword()) + .or().like("dictdata", pageRequest.getKeyword()) + ); + } + + // 排序 + if (StringUtils.hasText(pageRequest.getOrderBy())) { + if ("asc".equalsIgnoreCase(pageRequest.getOrderDirection())) { + queryWrapper.orderByAsc(pageRequest.getOrderBy()); + } else { + queryWrapper.orderByDesc(pageRequest.getOrderBy()); + } + } else { + queryWrapper.orderByAsc("dictcode", "orderno"); + } + + IPage result = appDictionaryService.page(page, queryWrapper); + return Result.success(result); + } + + @Operation(summary = "查询所有数据字典列表") + @GetMapping("/list") + @OperationLog(type = "06", module = "数据字典管理", description = "查询所有数据字典列表") + public Result> list() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByAsc("dictcode", "orderno"); + + List dictionaries = appDictionaryService.list(queryWrapper); + return Result.success(dictionaries); + } + + @Operation(summary = "根据ID查询数据字典详情") + @GetMapping("/{id}") + @OperationLog(type = "06", module = "数据字典管理", description = "查询数据字典详情") + public Result getById(@Parameter(description = "字典ID") @PathVariable String id) { + AppDictionary dictionary = appDictionaryService.getById(id); + return Result.success(dictionary); + } + + @Operation(summary = "根据字典编码查询字典项列表") + @GetMapping("/code/{dictCode}") + @OperationLog(type = "06", module = "数据字典管理", description = "根据字典编码查询字典项列表") + public Result> getByDictCode(@Parameter(description = "字典编码") @PathVariable String dictCode) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("dictcode", dictCode); + queryWrapper.orderByAsc("orderno"); + + List dictionaries = appDictionaryService.list(queryWrapper); + return Result.success(dictionaries); + } + + @Operation(summary = "根据字典编码和字典值查询字典项") + @GetMapping("/code/{dictCode}/data/{dictData}") + @OperationLog(type = "06", module = "数据字典管理", description = "根据字典编码和字典数据查询字典项") + public Result getByCodeAndData( + @Parameter(description = "字典编码") @PathVariable String dictCode, + @Parameter(description = "字典数据") @PathVariable String dictData) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("dictcode", dictCode); + queryWrapper.eq("dictdata", dictData); + + AppDictionary dictionary = appDictionaryService.getOne(queryWrapper); + return Result.success(dictionary); + } + + @Operation(summary = "新增数据字典") + @PostMapping + @OperationLog(type = "01", module = "数据字典管理", description = "新增数据字典") + public Result save(@RequestBody @Valid AppDictionary appDictionary) { + // 检查同一字典编码下的字典值是否已存在 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("dictcode", appDictionary.getDictcode()); + queryWrapper.eq("dictdata", appDictionary.getDictdata()); + AppDictionary existDictionary = appDictionaryService.getOne(queryWrapper); + if (existDictionary != null) { + return Result.error("该字典编码下的字典值已存在"); + } + + // 设置默认值 + if (appDictionary.getOrderno() == null) { + // 获取同一字典编码下的最大序号 + QueryWrapper orderQuery = new QueryWrapper<>(); + orderQuery.eq("dictcode", appDictionary.getDictcode()); + orderQuery.orderByDesc("orderno"); + orderQuery.last("LIMIT 1"); + AppDictionary lastDict = appDictionaryService.getOne(orderQuery); + appDictionary.setOrderno(lastDict != null ? lastDict.getOrderno() + 1 : 1); + } + + appDictionary.setLastmodifydate(LocalDateTime.now()); + boolean success = appDictionaryService.save(appDictionary); + return success ? Result.success("新增成功") : Result.error("新增失败"); + } + + @Operation(summary = "修改数据字典") + @PutMapping + @OperationLog(type = "02", module = "数据字典管理", description = "修改数据字典") + public Result update(@RequestBody @Valid AppDictionary appDictionary) { + // 检查字典是否存在 + AppDictionary existDictionary = appDictionaryService.getById(appDictionary.getId()); + if (existDictionary == null) { + return Result.error("数据字典不存在"); + } + + // 如果修改了字典编码或字典值,检查新的组合是否已被其他字典项使用 + if (!existDictionary.getDictcode().equals(appDictionary.getDictcode()) || + !existDictionary.getDictdata().equals(appDictionary.getDictdata())) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("dictcode", appDictionary.getDictcode()); + queryWrapper.eq("dictdata", appDictionary.getDictdata()); + queryWrapper.ne("id", appDictionary.getId()); + AppDictionary dictWithSameCodeValue = appDictionaryService.getOne(queryWrapper); + if (dictWithSameCodeValue != null) { + return Result.error("该字典编码下的字典数据已被其他字典项使用"); + } + } + + appDictionary.setLastmodifydate(LocalDateTime.now()); + boolean success = appDictionaryService.updateById(appDictionary); + return success ? Result.success("修改成功") : Result.error("修改失败"); + } + + @Operation(summary = "删除数据字典") + @DeleteMapping("/{id}") + @OperationLog(type = "03", module = "数据字典管理", description = "删除数据字典") + public Result delete(@Parameter(description = "字典ID") @PathVariable String id) { + boolean success = appDictionaryService.removeById(id); + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + @Operation(summary = "批量删除数据字典") + @DeleteMapping("/batch") + @OperationLog(type = "03", module = "数据字典管理", description = "批量删除数据字典") + public Result deleteBatch(@RequestBody List ids) { + boolean success = appDictionaryService.removeByIds(ids); + return success ? Result.success("批量删除成功") : Result.error("批量删除失败"); + } + + @Operation(summary = "根据字典编码删除所有字典项") + @DeleteMapping("/code/{dictCode}") + @OperationLog(type = "03", module = "数据字典管理", description = "根据字典编码删除所有字典项") + public Result deleteByDictCode(@Parameter(description = "字典编码") @PathVariable String dictCode) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("dictcode", dictCode); + + boolean success = appDictionaryService.remove(queryWrapper); + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + @Operation(summary = "根据字典名称获取字典数据") + @GetMapping("/name/{dictName}") + @OperationLog(type = "06", module = "数据字典管理", description = "根据字典名称获取字典数据") + public Result getDictDataByName(@Parameter(description = "字典名称") @PathVariable String dictName) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("dictname", dictName); + AppDictionary dictionary = appDictionaryService.getOne(queryWrapper); + + if (dictionary != null) { + return Result.success(dictionary.getDictdata()); + } + return Result.error("未找到对应的字典数据"); + } + + @Operation(summary = "获取所有字典编码列表") + @GetMapping("/codes") + @OperationLog(type = "06", module = "数据字典管理", description = "获取所有字典编码列表") + public Result> getDictCodes() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select("DISTINCT dictcode"); + queryWrapper.orderByAsc("dictcode"); + + List dictionaries = appDictionaryService.list(queryWrapper); + List dictCodes = dictionaries.stream() + .map(AppDictionary::getDictcode) + .distinct() + .collect(java.util.stream.Collectors.toList()); + + return Result.success(dictCodes); + } + + @Operation(summary = "调整字典项顺序") + @PutMapping("/reorder") + @OperationLog(type = "02", module = "数据字典管理", description = "调整字典项顺序") + public Result reorder(@RequestBody List orderRequests) { + for (DictOrderRequest request : orderRequests) { + AppDictionary dictionary = appDictionaryService.getById(request.getId()); + if (dictionary != null) { + dictionary.setOrderno(request.getOrderno()); + dictionary.setLastmodifydate(LocalDateTime.now()); + appDictionaryService.updateById(dictionary); + } + } + return Result.success("顺序调整成功"); + } + + @Operation(summary = "根据字典编码分组查询字典项") + @GetMapping("/grouped") + @OperationLog(type = "06", module = "数据字典管理", description = "根据字典编码分组查询字典项") + public Result>> getGroupedDictionaries() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByAsc("dictcode", "orderno"); + + List allDictionaries = appDictionaryService.list(queryWrapper); + java.util.Map> groupedDict = allDictionaries.stream() + .collect(java.util.stream.Collectors.groupingBy(AppDictionary::getDictcode)); + + return Result.success(groupedDict); + } + + /** + * 字典排序请求 + */ + public static class DictOrderRequest { + private String id; + private Integer orderno; + + public String getId() { return id; } + public void setId(String id) { this.id = id; } + public Integer getOrderno() { return orderno; } + public void setOrderno(Integer orderno) { this.orderno = orderno; } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AppMenuController.java b/backend/src/main/java/com/stdproject/controller/AppMenuController.java new file mode 100644 index 0000000..d8093e9 --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AppMenuController.java @@ -0,0 +1,378 @@ +package com.stdproject.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.stdproject.common.OperationLog; +import com.stdproject.common.PageRequest; +import com.stdproject.common.Result; +import com.stdproject.entity.AppMenu; +import com.stdproject.service.IAppMenuService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + *

+ * 应用-菜单表 前端控制器 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Tag(name = "菜单管理", description = "菜单添加、菜单修改、菜单删除、菜单查询等功能") +@RestController +@RequestMapping("/app-menu") +public class AppMenuController { + + @Autowired + private IAppMenuService appMenuService; + + @Operation(summary = "分页查询菜单列表") + @PostMapping("/page") + @OperationLog(type = "06", module = "菜单管理", description = "分页查询菜单列表") + public Result> page(@RequestBody @Valid PageRequest pageRequest) { + Page page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 关键字搜索 + if (StringUtils.hasText(pageRequest.getKeyword())) { + queryWrapper.and(wrapper -> wrapper + .like("name", pageRequest.getKeyword()) + .or().like("code", pageRequest.getKeyword()) + .or().like("url", pageRequest.getKeyword()) + ); + } + + // 排序 + if (StringUtils.hasText(pageRequest.getOrderBy())) { + if ("asc".equalsIgnoreCase(pageRequest.getOrderDirection())) { + queryWrapper.orderByAsc(pageRequest.getOrderBy()); + } else { + queryWrapper.orderByDesc(pageRequest.getOrderBy()); + } + } else { + queryWrapper.orderByAsc("parentid", "orderno"); + } + + IPage result = appMenuService.page(page, queryWrapper); + return Result.success(result); + } + + @Operation(summary = "查询所有菜单列表") + @GetMapping("/list") + @OperationLog(type = "06", module = "菜单管理", description = "查询所有菜单列表") + public Result> list() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByAsc("parentid", "orderno"); + + List menus = appMenuService.list(queryWrapper); + return Result.success(menus); + } + + @Operation(summary = "获取菜单树形结构") + @GetMapping("/tree") + @OperationLog(type = "06", module = "菜单管理", description = "获取菜单树形结构") + public Result> getMenuTree() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByAsc("parentid", "orderno"); + + List allMenus = appMenuService.list(queryWrapper); + List tree = buildMenuTree(allMenus, "0"); + return Result.success(tree); + } + + @Operation(summary = "根据ID查询菜单详情") + @GetMapping("/{id}") + @OperationLog(type = "06", module = "菜单管理", description = "查询菜单详情") + public Result getById(@Parameter(description = "菜单ID") @PathVariable String id) { + AppMenu menu = appMenuService.getById(id); + return Result.success(menu); + } + + @Operation(summary = "根据父级ID查询子菜单") + @GetMapping("/children/{parentId}") + @OperationLog(type = "06", module = "菜单管理", description = "根据父级ID查询子菜单") + public Result> getChildren(@Parameter(description = "父级菜单ID") @PathVariable String parentId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("parentid", parentId); + queryWrapper.orderByAsc("orderno"); + + List children = appMenuService.list(queryWrapper); + return Result.success(children); + } + + @Operation(summary = "新增菜单") + @PostMapping + @OperationLog(type = "01", module = "菜单管理", description = "新增菜单") + public Result save(@RequestBody @Valid AppMenu appMenu) { + // 检查菜单编号是否已存在 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("code", appMenu.getCode()); + AppMenu existMenu = appMenuService.getOne(queryWrapper); + if (existMenu != null) { + return Result.error("菜单编号已存在"); + } + + // 检查父级菜单是否存在(如果不是顶级菜单) + if (!"0".equals(appMenu.getParentid())) { + AppMenu parentMenu = appMenuService.getById(appMenu.getParentid()); + if (parentMenu == null) { + return Result.error("父级菜单不存在"); + } + } + + // 设置默认值 + if (appMenu.getOrderno() == null) { + // 获取同级菜单的最大序号 + QueryWrapper orderQuery = new QueryWrapper<>(); + orderQuery.eq("parentid", appMenu.getParentid()); + orderQuery.orderByDesc("orderno"); + orderQuery.last("LIMIT 1"); + AppMenu lastMenu = appMenuService.getOne(orderQuery); + appMenu.setOrderno(lastMenu != null ? lastMenu.getOrderno() + 1 : 1); + } + + if (!StringUtils.hasText(appMenu.getIsdisplay())) { + appMenu.setIsdisplay("1"); + } + + if (!StringUtils.hasText(appMenu.getIslink())) { + appMenu.setIslink("0"); + } + + if (!StringUtils.hasText(appMenu.getType())) { + appMenu.setType("01"); + } + + appMenu.setLastmodifydate(LocalDateTime.now()); + boolean success = appMenuService.save(appMenu); + return success ? Result.success("新增成功") : Result.error("新增失败"); + } + + @Operation(summary = "修改菜单") + @PutMapping + @OperationLog(type = "02", module = "菜单管理", description = "修改菜单") + public Result update(@RequestBody @Valid AppMenu appMenu) { + // 检查菜单是否存在 + AppMenu existMenu = appMenuService.getById(appMenu.getId()); + if (existMenu == null) { + return Result.error("菜单不存在"); + } + + // 如果修改了菜单编号,检查新编号是否已被其他菜单使用 + if (!existMenu.getCode().equals(appMenu.getCode())) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("code", appMenu.getCode()); + queryWrapper.ne("id", appMenu.getId()); + AppMenu menuWithSameCode = appMenuService.getOne(queryWrapper); + if (menuWithSameCode != null) { + return Result.error("菜单编号已被其他菜单使用"); + } + } + + // 如果修改了父级菜单,检查是否会形成循环引用 + if (!existMenu.getParentid().equals(appMenu.getParentid())) { + if (isCircularReference(appMenu.getId(), appMenu.getParentid())) { + return Result.error("不能将菜单移动到自己的子菜单下"); + } + + // 检查父级菜单是否存在(如果不是顶级菜单) + if (!"0".equals(appMenu.getParentid())) { + AppMenu parentMenu = appMenuService.getById(appMenu.getParentid()); + if (parentMenu == null) { + return Result.error("父级菜单不存在"); + } + } + } + + appMenu.setLastmodifydate(LocalDateTime.now()); + boolean success = appMenuService.updateById(appMenu); + return success ? Result.success("修改成功") : Result.error("修改失败"); + } + + @Operation(summary = "删除菜单") + @DeleteMapping("/{id}") + @OperationLog(type = "03", module = "菜单管理", description = "删除菜单") + public Result delete(@Parameter(description = "菜单ID") @PathVariable String id) { + // 检查是否有子菜单 + QueryWrapper childQuery = new QueryWrapper<>(); + childQuery.eq("parentid", id); + long childCount = appMenuService.count(childQuery); + if (childCount > 0) { + return Result.error("存在子菜单,无法删除"); + } + + boolean success = appMenuService.removeById(id); + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + @Operation(summary = "批量删除菜单") + @DeleteMapping("/batch") + @OperationLog(type = "03", module = "菜单管理", description = "批量删除菜单") + public Result deleteBatch(@RequestBody List ids) { + for (String id : ids) { + // 检查是否有子菜单 + QueryWrapper childQuery = new QueryWrapper<>(); + childQuery.eq("parentid", id); + long childCount = appMenuService.count(childQuery); + if (childCount > 0) { + return Result.error("存在子菜单的菜单无法删除"); + } + } + + boolean success = appMenuService.removeByIds(ids); + return success ? Result.success("批量删除成功") : Result.error("批量删除失败"); + } + + @Operation(summary = "根据菜单类型查询菜单列表") + @GetMapping("/type/{type}") + @OperationLog(type = "06", module = "菜单管理", description = "根据菜单类型查询菜单列表") + public Result> getByType(@Parameter(description = "菜单类型") @PathVariable String type) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("type", type); + queryWrapper.orderByAsc("parentid", "orderno"); + + List menus = appMenuService.list(queryWrapper); + return Result.success(menus); + } + + @Operation(summary = "获取显示的菜单树") + @GetMapping("/display-tree") + @OperationLog(type = "06", module = "菜单管理", description = "获取显示的菜单树") + public Result> getDisplayMenuTree() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("isdisplay", "1"); + queryWrapper.orderByAsc("parentid", "orderno"); + + List displayMenus = appMenuService.list(queryWrapper); + List tree = buildMenuTree(displayMenus, "0"); + return Result.success(tree); + } + + @Operation(summary = "调整菜单顺序") + @PutMapping("/reorder") + @OperationLog(type = "02", module = "菜单管理", description = "调整菜单顺序") + public Result reorder(@RequestBody List orderRequests) { + for (MenuOrderRequest request : orderRequests) { + AppMenu menu = appMenuService.getById(request.getId()); + if (menu != null) { + menu.setOrderno(request.getOrderno()); + menu.setLastmodifydate(LocalDateTime.now()); + appMenuService.updateById(menu); + } + } + return Result.success("顺序调整成功"); + } + + /** + * 构建菜单树 + */ + private List buildMenuTree(List allMenus, String parentId) { + return allMenus.stream() + .filter(menu -> parentId.equals(menu.getParentid())) + .map(menu -> { + MenuTreeNode node = new MenuTreeNode(); + node.setId(menu.getId()); + node.setCode(menu.getCode()); + node.setName(menu.getName()); + node.setIcon(menu.getIcon()); + node.setUrl(menu.getUrl()); + node.setType(menu.getType()); + node.setIslink(menu.getIslink()); + node.setIsdisplay(menu.getIsdisplay()); + node.setOrderno(menu.getOrderno()); + node.setParentid(menu.getParentid()); + node.setModuleId(menu.getModuleId()); + node.setChildren(buildMenuTree(allMenus, menu.getId())); + return node; + }) + .collect(Collectors.toList()); + } + + /** + * 检查是否会形成循环引用 + */ + private boolean isCircularReference(String menuId, String newParentId) { + if ("0".equals(newParentId)) { + return false; + } + + if (menuId.equals(newParentId)) { + return true; + } + + AppMenu parentMenu = appMenuService.getById(newParentId); + if (parentMenu == null) { + return false; + } + + return isCircularReference(menuId, parentMenu.getParentid()); + } + + /** + * 菜单树节点 + */ + public static class MenuTreeNode { + private String id; + private String code; + private String name; + private String icon; + private String url; + private String type; + private String islink; + private String isdisplay; + private Integer orderno; + private String parentid; + private String moduleId; + private List children = new ArrayList<>(); + + // Getters and Setters + public String getId() { return id; } + public void setId(String id) { this.id = id; } + public String getCode() { return code; } + public void setCode(String code) { this.code = code; } + public String getName() { return name; } + public void setName(String name) { this.name = name; } + public String getIcon() { return icon; } + public void setIcon(String icon) { this.icon = icon; } + public String getUrl() { return url; } + public void setUrl(String url) { this.url = url; } + public String getType() { return type; } + public void setType(String type) { this.type = type; } + public String getIslink() { return islink; } + public void setIslink(String islink) { this.islink = islink; } + public String getIsdisplay() { return isdisplay; } + public void setIsdisplay(String isdisplay) { this.isdisplay = isdisplay; } + public Integer getOrderno() { return orderno; } + public void setOrderno(Integer orderno) { this.orderno = orderno; } + public String getParentid() { return parentid; } + public void setParentid(String parentid) { this.parentid = parentid; } + public String getModuleId() { return moduleId; } + public void setModuleId(String moduleId) { this.moduleId = moduleId; } + public List getChildren() { return children; } + public void setChildren(List children) { this.children = children; } + } + + /** + * 菜单排序请求 + */ + public static class MenuOrderRequest { + private String id; + private Integer orderno; + + public String getId() { return id; } + public void setId(String id) { this.id = id; } + public Integer getOrderno() { return orderno; } + public void setOrderno(Integer orderno) { this.orderno = orderno; } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AppOptLogController.java b/backend/src/main/java/com/stdproject/controller/AppOptLogController.java new file mode 100644 index 0000000..dd5a61c --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AppOptLogController.java @@ -0,0 +1,248 @@ +package com.stdproject.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.stdproject.common.OperationLog; +import com.stdproject.common.PageRequest; +import com.stdproject.common.Result; +import com.stdproject.entity.AppOptLog; +import com.stdproject.service.IAppOptLogService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 应用-操作日志表 前端控制器 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Tag(name = "操作日志管理", description = "操作日志查询、操作日志删除等功能") +@RestController +@RequestMapping("/api/optlog") +public class AppOptLogController { + + @Autowired + private IAppOptLogService appOptLogService; + + @Operation(summary = "分页查询操作日志列表") + @PostMapping("/page") + @OperationLog(type = "06", module = "操作日志管理", description = "分页查询操作日志列表") + public Result> page(@RequestBody @Valid PageRequest pageRequest) { + Page page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 关键字搜索 + if (StringUtils.hasText(pageRequest.getKeyword())) { + queryWrapper.and(wrapper -> wrapper + .like("username", pageRequest.getKeyword()) + .or().like("module", pageRequest.getKeyword()) + .or().like("description", pageRequest.getKeyword()) + ); + } + + // 排序 + if (StringUtils.hasText(pageRequest.getOrderBy())) { + if ("asc".equalsIgnoreCase(pageRequest.getOrderDirection())) { + queryWrapper.orderByAsc(pageRequest.getOrderBy()); + } else { + queryWrapper.orderByDesc(pageRequest.getOrderBy()); + } + } else { + queryWrapper.orderByDesc("logtime"); + } + + IPage result = appOptLogService.page(page, queryWrapper); + return Result.success(result); + } + + @Operation(summary = "根据ID查询操作日志详情") + @GetMapping("/{id}") + @OperationLog(type = "06", module = "操作日志管理", description = "查询操作日志详情") + public Result getById(@Parameter(description = "日志ID") @PathVariable String id) { + AppOptLog optLog = appOptLogService.getById(id); + return Result.success(optLog); + } + + @Operation(summary = "根据用户名查询操作日志") + @GetMapping("/user/{username}") + @OperationLog(type = "06", module = "操作日志管理", description = "根据用户名查询操作日志") + public Result> getByUsername( + @Parameter(description = "用户名") @PathVariable String username, + @Parameter(description = "限制条数") @RequestParam(defaultValue = "100") Integer limit) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("username", username); + queryWrapper.orderByDesc("logtime"); + queryWrapper.last("LIMIT " + limit); + + List logs = appOptLogService.list(queryWrapper); + return Result.success(logs); + } + + @Operation(summary = "根据操作类型查询操作日志") + @GetMapping("/type/{type}") + @OperationLog(type = "06", module = "操作日志管理", description = "根据操作类型查询操作日志") + public Result> getByType( + @Parameter(description = "操作类型") @PathVariable String type, + @Parameter(description = "限制条数") @RequestParam(defaultValue = "100") Integer limit) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("type", type); + queryWrapper.orderByDesc("logtime"); + queryWrapper.last("LIMIT " + limit); + + List logs = appOptLogService.list(queryWrapper); + return Result.success(logs); + } + + @Operation(summary = "根据模块查询操作日志") + @GetMapping("/module/{module}") + @OperationLog(type = "06", module = "操作日志管理", description = "根据模块查询操作日志") + public Result> getByModule( + @Parameter(description = "模块名称") @PathVariable String module, + @Parameter(description = "限制条数") @RequestParam(defaultValue = "100") Integer limit) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("module", module); + queryWrapper.orderByDesc("opttime"); + queryWrapper.last("LIMIT " + limit); + + List logs = appOptLogService.list(queryWrapper); + return Result.success(logs); + } + + @Operation(summary = "根据时间范围查询操作日志") + @GetMapping("/time-range") + @OperationLog(type = "06", module = "操作日志管理", description = "根据时间范围查询操作日志") + public Result> getByTimeRange( + @Parameter(description = "开始时间") @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime, + @Parameter(description = "结束时间") @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime, + @Parameter(description = "限制条数") @RequestParam(defaultValue = "1000") Integer limit) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.between("opttime", startTime, endTime); + queryWrapper.orderByDesc("opttime"); + queryWrapper.last("LIMIT " + limit); + + List logs = appOptLogService.list(queryWrapper); + return Result.success(logs); + } + + @Operation(summary = "根据IP地址查询操作日志") + @GetMapping("/ip/{ip}") + @OperationLog(type = "06", module = "操作日志管理", description = "根据IP地址查询操作日志") + public Result> getByIp( + @Parameter(description = "IP地址") @PathVariable String ip, + @Parameter(description = "限制条数") @RequestParam(defaultValue = "100") Integer limit) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("ip", ip); + queryWrapper.orderByDesc("opttime"); + queryWrapper.last("LIMIT " + limit); + + List logs = appOptLogService.list(queryWrapper); + return Result.success(logs); + } + + + @Operation(summary = "删除操作日志") + @DeleteMapping("/{id}") + @OperationLog(type = "03", module = "操作日志管理", description = "删除操作日志") + public Result delete(@Parameter(description = "日志ID") @PathVariable String id) { + boolean success = appOptLogService.removeById(id); + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + @Operation(summary = "批量删除操作日志") + @DeleteMapping("/batch") + @OperationLog(type = "03", module = "操作日志管理", description = "批量删除操作日志") + public Result deleteBatch(@RequestBody List ids) { + boolean success = appOptLogService.removeByIds(ids); + return success ? Result.success("批量删除成功") : Result.error("批量删除失败"); + } + + @Operation(summary = "清理指定天数前的操作日志") + @DeleteMapping("/clean/{days}") + @OperationLog(type = "03", module = "操作日志管理", description = "清理历史操作日志") + public Result cleanOldLogs(@Parameter(description = "保留天数") @PathVariable Integer days) { + LocalDateTime cutoffTime = LocalDateTime.now().minusDays(days); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lt("logtime", cutoffTime); + + boolean success = appOptLogService.remove(queryWrapper); + return success ? Result.success("清理成功") : Result.error("清理失败"); + } + + @Operation(summary = "获取操作日志统计信息") + @GetMapping("/statistics") + @OperationLog(type = "06", module = "操作日志管理", description = "获取操作日志统计信息") + public Result getStatistics() { + // 总日志数 + long totalCount = appOptLogService.count(); + + // 今日日志数 + LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0); + QueryWrapper todayQuery = new QueryWrapper<>(); + todayQuery.ge("opttime", todayStart); + long todayCount = appOptLogService.count(todayQuery); + + // 本周日志数 + LocalDateTime weekStart = LocalDateTime.now().minusDays(7); + QueryWrapper weekQuery = new QueryWrapper<>(); + weekQuery.ge("logtime", weekStart); + long weekCount = appOptLogService.count(weekQuery); + + // 本月日志数 + LocalDateTime monthStart = LocalDateTime.now().minusDays(30); + QueryWrapper monthQuery = new QueryWrapper<>(); + monthQuery.ge("logtime", monthStart); + long monthCount = appOptLogService.count(monthQuery); + + LogStatistics statistics = new LogStatistics(); + statistics.setTotalCount(totalCount); + statistics.setTodayCount(todayCount); + statistics.setWeekCount(weekCount); + statistics.setMonthCount(monthCount); + + return Result.success(statistics); + } + + @Operation(summary = "获取最近的操作日志") + @GetMapping("/recent") + @OperationLog(type = "06", module = "操作日志管理", description = "获取最近的操作日志") + public Result> getRecentLogs( + @Parameter(description = "限制条数") @RequestParam(defaultValue = "50") Integer limit) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByDesc("logtime"); + queryWrapper.last("LIMIT " + limit); + + List logs = appOptLogService.list(queryWrapper); + return Result.success(logs); + } + + /** + * 日志统计信息 + */ + public static class LogStatistics { + private Long totalCount; + private Long todayCount; + private Long weekCount; + private Long monthCount; + + public Long getTotalCount() { return totalCount; } + public void setTotalCount(Long totalCount) { this.totalCount = totalCount; } + public Long getTodayCount() { return todayCount; } + public void setTodayCount(Long todayCount) { this.todayCount = todayCount; } + public Long getWeekCount() { return weekCount; } + public void setWeekCount(Long weekCount) { this.weekCount = weekCount; } + public Long getMonthCount() { return monthCount; } + public void setMonthCount(Long monthCount) { this.monthCount = monthCount; } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AppOrganizationController.java b/backend/src/main/java/com/stdproject/controller/AppOrganizationController.java new file mode 100644 index 0000000..1feb644 --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AppOrganizationController.java @@ -0,0 +1,221 @@ +package com.stdproject.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.stdproject.common.OperationLog; +import com.stdproject.common.Result; +import com.stdproject.entity.AppOrganization; +import com.stdproject.service.IAppOrganizationService; +import com.stdproject.service.IAppUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 应用-组织机构 前端控制器 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Tag(name = "组织管理", description = "组织添加、组织修改、组织删除、组织查询等功能,支持公司和部门两级树形结构") +@RestController +@RequestMapping("/api/org") +public class AppOrganizationController { + + @Autowired + private IAppOrganizationService appOrganizationService; + // 需要在类开头注入 IAppUserService + @Autowired + private IAppUserService appUserService; + + @Operation(summary = "查询公司结构树") + @GetMapping("/getCompanyTree") + @OperationLog(type = "06", module = "组织管理", description = "查询公司结构树") + public Result> getCompanyTree() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("orgtype", "01"); + queryWrapper.eq("isvaild", "1"); + queryWrapper.orderByAsc("orgcode"); + List children = appOrganizationService.list(queryWrapper); + return Result.success(children); + } + + @Operation(summary = "查询部门列表") + @GetMapping("/getDepartmentList") + @OperationLog(type = "06", module = "组织管理", description = "查询部门列表") + public Result> getDepartmentList(@RequestParam String parentid,@RequestParam String keystr) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("orgtype", "02"); + queryWrapper.eq("parentid", parentid); + queryWrapper.eq("isvaild", "1"); + if (StringUtils.hasText(keystr)) { + queryWrapper.and(wrapper -> wrapper + .like("orgname", keystr) + .or().like("orgcode", keystr) + .or().like("description", keystr) + ); + } + queryWrapper.orderByAsc("orgcode"); + List children = appOrganizationService.list(queryWrapper); + return Result.success(children); + } + + + + @Operation(summary = "根据ID查询组织详情") + @GetMapping("getDetailById/{id}") + @OperationLog(type = "06", module = "组织管理", description = "根据ID查询组织详情") + public Result getDetailById(@PathVariable String id) { + AppOrganization organization = appOrganizationService.getById(id); + return Result.success(organization); + } + + + @Operation(summary = "新增组织") + @PostMapping("add") + @OperationLog(type = "01", module = "组织管理", description = "新增组织") + public Result add(@RequestBody @Valid AppOrganization appOrganization) { + // 设置默认值 + //生成新的组织编号 公司编号:010101 部门编号:0001 + appOrganization.setOrgcode(getNewOrgCode(appOrganization.getOrgtype(), appOrganization.getParentid())); + //设置状态为有效 + appOrganization.setIsvaild("1"); + // 从当前登录用户上下文中获取用户名 + appOrganization.setLastmodifier(appUserService.getCurrentUsername()); + appOrganization.setLastmodifydate(LocalDateTime.now()); + boolean success = appOrganizationService.save(appOrganization); + return success ? Result.success("新增成功") : Result.error("新增失败"); + } + + @Operation(summary = "修改组织") + @PostMapping("update") + @OperationLog(type = "02", module = "组织管理", description = "修改组织") + public Result update(@RequestBody @Valid AppOrganization appOrganization) { + // 检查组织是否存在 + AppOrganization existOrg = appOrganizationService.getById(appOrganization.getId()); + if (existOrg == null) { + return Result.error("组织不存在"); + } + // 验证父级组织变更的合法性 + if (StringUtils.hasText(appOrganization.getParentid()) && !"0".equals(appOrganization.getParentid())) { + // 不能将自己设为父级 + if (appOrganization.getId().equals(appOrganization.getParentid())) { + return Result.error("不能将自己设为父级组织"); + } + // 验证父级组织是否存在 + AppOrganization parent = appOrganizationService.getById(appOrganization.getParentid()); + if (parent == null || !"1".equals(parent.getIsvaild())) { + return Result.error("父级组织不存在或已禁用"); + } + + if ("02".equals(parent.getOrgtype())) { + return Result.error("部门下不能有子组织"); + } + } + appOrganization.setLastmodifier(appUserService.getCurrentUsername()); + appOrganization.setLastmodifydate(LocalDateTime.now()); + boolean success = appOrganizationService.updateById(appOrganization); + return success ? Result.success("修改成功") : Result.error("修改失败"); + } + + @Operation(summary = "删除组织") + @PostMapping("delete/{id}") + @OperationLog(type = "03", module = "组织管理", description = "删除组织") + public Result delete(@PathVariable String id) { + boolean success = appOrganizationService.removeById(id); + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + /** + * 根据组织类型和父节点生成新的组织编码 + * + * @param orgType 组织类型:"01"表示公司,"02"表示部门 + * @param parentId 父节点ID,新增部门时使用 + * @return 新的组织编码 + */ + private String getNewOrgCode(String orgType, String parentId) { + if ("01".equals(orgType)) { + // 公司类型:查找当前最大的公司编码并递增最后一级 + AppOrganization parentOrg = null; + if (StringUtils.hasText(parentId) && !"0".equals(parentId)) { + parentOrg = appOrganizationService.getById(parentId); + if (parentOrg == null || !"1".equals(parentOrg.getIsvaild())) { + throw new IllegalArgumentException("无效的父级组织"); + } + } + + // 获取父节点编码(顶级为“01”) + String parentCode = parentOrg != null ? parentOrg.getOrgcode() : "01"; + + // 获取当前父节点下的最大子节点编码 + String maxCompanyCode = getMaxCodeByParentId("01",parentId); + + int nextLevel = 1; + if (maxCompanyCode != null && !maxCompanyCode.isEmpty()) { + try { + // 提取最后两位 + String lastTwo = maxCompanyCode.substring(maxCompanyCode.length() - 2); + nextLevel = Integer.parseInt(lastTwo) + 1; + } catch (Exception e) { + nextLevel = 1; // 出错则重置为1 + } + } + + if (nextLevel > 99) { + throw new RuntimeException("公司编码已达上限,请联系管理员处理"); + } + + return parentCode + String.format("%02d", nextLevel); + } else if ("02".equals(orgType) && StringUtils.hasText(parentId)) { + // 部门类型:查找该公司下最大部门编码并递增 + AppOrganization parentOrg = appOrganizationService.getById(parentId); + if (parentOrg == null || !"1".equals(parentOrg.getIsvaild())) { + throw new IllegalArgumentException("无效的父级组织"); + } + + // 获取该父节点下最大部门编号 + String maxDeptCodeStr = getMaxCodeByParentId("02",parentId); + int nextSeq = 1; + + if (maxDeptCodeStr != null && !maxDeptCodeStr.isEmpty()) { + try { + nextSeq = Integer.parseInt(maxDeptCodeStr) + 1; + } catch (NumberFormatException e) { + nextSeq = 1; + } + } + + if (nextSeq > 9999) { + throw new RuntimeException("部门编码已达上限,请联系管理员处理"); + } + + return String.format("%04d", nextSeq); + } else { + throw new IllegalArgumentException("无法生成组织编码:参数不完整"); + } + } + + + private String getMaxCodeByParentId(String orgType,String parentId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(AppOrganization::getOrgtype, orgType) + .eq(AppOrganization::getParentid, parentId) + .eq(AppOrganization::getIsvaild, "1") + .orderByDesc(AppOrganization::getOrgcode) + .select(AppOrganization::getOrgcode) + .last("LIMIT 1"); + // 使用selectList方法获取符合条件的记录列表 + List list = appOrganizationService.list(queryWrapper); + // 如果列表不为空,返回第一个记录的orgcode + return list.isEmpty() ? null : list.get(0).getOrgcode(); + } + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AppRoleController.java b/backend/src/main/java/com/stdproject/controller/AppRoleController.java new file mode 100644 index 0000000..6f660a9 --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AppRoleController.java @@ -0,0 +1,320 @@ +package com.stdproject.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.stdproject.common.OperationLog; +import com.stdproject.common.PageRequest; +import com.stdproject.common.Result; +import com.stdproject.entity.AppRole; +import com.stdproject.entity.AppRoleMenu; +import com.stdproject.entity.AppRoleUser; +import com.stdproject.service.IAppRoleMenuService; +import com.stdproject.service.IAppRoleService; +import com.stdproject.service.IAppRoleUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; + +/** + *

+ * 应用-角色表 前端控制器 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Tag(name = "角色管理", description = "角色添加、角色修改、角色删除、角色查询,角色权限分配等功能") +@RestController +@RequestMapping("/api/role") +public class AppRoleController { + + @Autowired + private IAppRoleService appRoleService; + + @Autowired + private IAppRoleMenuService appRoleMenuService; + + @Autowired + private IAppRoleUserService appRoleUserService; + + @Operation(summary = "分页查询角色列表") + @PostMapping("/page") + @OperationLog(type = "06", module = "角色管理", description = "分页查询角色列表") + public Result> page(@RequestBody @Valid PageRequest pageRequest) { + Page page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 关键字搜索 + if (StringUtils.hasText(pageRequest.getKeyword())) { + queryWrapper.and(wrapper -> wrapper + .like("rolename", pageRequest.getKeyword()) + .or().like("rolecode", pageRequest.getKeyword()) + .or().like("description", pageRequest.getKeyword()) + ); + } + + // 只查询有效的角色 + queryWrapper.eq("isvaild", "1"); + + // 排序 + if (StringUtils.hasText(pageRequest.getOrderBy())) { + if ("asc".equalsIgnoreCase(pageRequest.getOrderDirection())) { + queryWrapper.orderByAsc(pageRequest.getOrderBy()); + } else { + queryWrapper.orderByDesc(pageRequest.getOrderBy()); + } + } else { + queryWrapper.orderByAsc("rolecode"); + } + + IPage result = appRoleService.page(page, queryWrapper); + return Result.success(result); + } + + @Operation(summary = "查询所有有效角色列表") + @GetMapping("/list") + @OperationLog(type = "06", module = "角色管理", description = "查询所有有效角色列表") + public Result> list() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("isvaild", "1"); + queryWrapper.orderByAsc("rolecode"); + + List roles = appRoleService.list(queryWrapper); + return Result.success(roles); + } + + @Operation(summary = "根据ID查询角色详情") + @GetMapping("/{id}") + @OperationLog(type = "06", module = "角色管理", description = "查询角色详情") + public Result getById(@Parameter(description = "角色ID") @PathVariable String id) { + AppRole role = appRoleService.getById(id); + return Result.success(role); + } + @Operation(summary = "新增角色") + @PostMapping + @OperationLog(type = "01", module = "角色管理", description = "新增角色") + public Result save(@RequestBody @Valid AppRole appRole) { + // 检查角色名称是否已存在 + QueryWrapper nameQuery = new QueryWrapper<>(); + nameQuery.eq("rolename", appRole.getRolename()); + nameQuery.eq("isvaild", "1"); + AppRole existRoleName = appRoleService.getOne(nameQuery); + if (ObjectUtils.isNotEmpty(existRoleName)) { + return Result.error("角色名称已存在"); + } + // 自动生成角色编号 + String maxRoleCode = getMaxRoleCode(); + String newRoleCode; + if (maxRoleCode == null) { + newRoleCode = "001"; + } else { + int nextCode = Integer.parseInt(maxRoleCode) + 1; + newRoleCode = String.format("%03d", nextCode); + } + appRole.setRolecode(newRoleCode); + // 设置默认值 + appRole.setIsvaild("1"); + appRole.setLastmodifier("admin"); + appRole.setLastmodifydate(LocalDateTime.now()); + boolean success = appRoleService.save(appRole); + return success ? Result.success("新增成功") : Result.error("新增失败"); + } + + /** + * 获取最大的角色编号 + * @return 最大角色编号 + */ + private String getMaxRoleCode() { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(AppRole::getIsvaild, "1") + .orderByDesc(AppRole::getRolecode) + .select(AppRole::getRolecode) + .last("LIMIT 1"); + List list = appRoleService.list(queryWrapper); + return list.isEmpty() ? null : list.get(0).getRolecode(); + } + + @Operation(summary = "修改角色") + @PutMapping + @OperationLog(type = "02", module = "角色管理", description = "修改角色") + public Result update(@RequestBody @Valid AppRole appRole) { + // 检查角色是否存在 + AppRole existRole = appRoleService.getById(appRole.getId()); + if (existRole == null) { + return Result.error("角色不存在"); + } + + // 如果修改了角色名称,检查新名称是否已被其他角色使用 + if (!existRole.getRolename().equals(appRole.getRolename())) { + QueryWrapper nameQuery = new QueryWrapper<>(); + nameQuery.eq("rolename", appRole.getRolename()); + nameQuery.eq("isvaild", "1"); + nameQuery.ne("id", appRole.getId()); + AppRole roleWithSameName = appRoleService.getOne(nameQuery); + if (roleWithSameName != null) { + return Result.error("角色名称已被其他角色使用"); + } + } + appRole.setLastmodifier("admin"); + appRole.setLastmodifydate(LocalDateTime.now()); + boolean success = appRoleService.updateById(appRole); + return success ? Result.success("修改成功") : Result.error("修改失败"); + } + + @Operation(summary = "删除角色") + @DeleteMapping("/{id}") + @OperationLog(type = "03", module = "角色管理", description = "删除角色") + public Result delete(@Parameter(description = "角色ID") @PathVariable String id) { + // 检查是否有用户关联此角色 + QueryWrapper userQuery = new QueryWrapper<>(); + userQuery.eq("roleid", id); + long userCount = appRoleUserService.count(userQuery); + if (userCount > 0) { + return Result.error("存在用户关联此角色,无法删除"); + } + + // 软删除:设置为无效 + AppRole role = appRoleService.getById(id); + if (role != null) { + role.setIsvaild("0"); + role.setLastmodifydate(LocalDateTime.now()); + boolean success = appRoleService.updateById(role); + + if (success) { + // 同时删除角色菜单关联 + QueryWrapper menuQuery = new QueryWrapper<>(); + menuQuery.eq("roleid", id); + appRoleMenuService.remove(menuQuery); + } + + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + return Result.error("角色不存在"); + } + + + + @Operation(summary = "根据角色类型查询角色列表") + @GetMapping("/type/{type}") + @OperationLog(type = "06", module = "角色管理", description = "根据角色类型查询角色列表") + public Result> getByType(@Parameter(description = "角色类型:1-应用管理员,2-应用普通用户") @PathVariable String type) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("type", type); + queryWrapper.eq("isvaild", "1"); + queryWrapper.orderByAsc("rolecode"); + List roles = appRoleService.list(queryWrapper); + return Result.success(roles); + } + + @Operation(summary = "分配角色菜单权限") + @PostMapping("/assign-menus/{roleId}") + @OperationLog(type = "02", module = "角色管理", description = "分配角色菜单权限") + public Result assignMenus( + @Parameter(description = "角色ID") @PathVariable String roleId, + @RequestBody List menuIds) { + + // 检查角色是否存在 + AppRole role = appRoleService.getById(roleId); + if (role == null || !"1".equals(role.getIsvaild())) { + return Result.error("角色不存在或已禁用"); + } + + // 先删除原有的菜单权限 + QueryWrapper deleteQuery = new QueryWrapper<>(); + deleteQuery.eq("roleid", roleId); + appRoleMenuService.remove(deleteQuery); + + // 添加新的菜单权限 + if (menuIds != null && !menuIds.isEmpty()) { + List roleMenus = menuIds.stream().map(menuId -> { + AppRoleMenu roleMenu = new AppRoleMenu(); + roleMenu.setRoleid(roleId); + roleMenu.setMenuid(menuId); + roleMenu.setAppId(role.getAppId()); + return roleMenu; + }).collect(Collectors.toList()); + + boolean success = appRoleMenuService.saveBatch(roleMenus); + return success ? Result.success("权限分配成功") : Result.error("权限分配失败"); + } + + return Result.success("权限分配成功"); + } + + @Operation(summary = "获取角色的菜单权限") + @GetMapping("/menus/{roleId}") + @OperationLog(type = "06", module = "角色管理", description = "获取角色的菜单权限") + public Result> getRoleMenus(@Parameter(description = "角色ID") @PathVariable String roleId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("roleid", roleId); + + List roleMenus = appRoleMenuService.list(queryWrapper); + List menuIds = roleMenus.stream() + .map(AppRoleMenu::getMenuid) + .collect(Collectors.toList()); + + return Result.success(menuIds); + } + + @Operation(summary = "分配用户角色") + @PostMapping("/assign-users/{roleId}") + @OperationLog(type = "02", module = "角色管理", description = "分配用户角色") + public Result assignUsers( + @Parameter(description = "角色ID") @PathVariable String roleId, + @RequestBody List userIds) { + + // 检查角色是否存在 + AppRole role = appRoleService.getById(roleId); + if (role == null || !"1".equals(role.getIsvaild())) { + return Result.error("角色不存在或已禁用"); + } + + // 先删除原有的用户角色关联 + QueryWrapper deleteQuery = new QueryWrapper<>(); + deleteQuery.eq("roleid", roleId); + appRoleUserService.remove(deleteQuery); + + // 添加新的用户角色关联 + if (userIds != null && !userIds.isEmpty()) { + List roleUsers = userIds.stream().map(userId -> { + AppRoleUser roleUser = new AppRoleUser(); + roleUser.setRoleid(roleId); + roleUser.setUserid(userId); + roleUser.setAppId(role.getAppId()); + return roleUser; + }).collect(Collectors.toList()); + + boolean success = appRoleUserService.saveBatch(roleUsers); + return success ? Result.success("用户分配成功") : Result.error("用户分配失败"); + } + + return Result.success("用户分配成功"); + } + + @Operation(summary = "获取角色的用户列表") + @GetMapping("/users/{roleId}") + @OperationLog(type = "06", module = "角色管理", description = "获取角色的用户列表") + public Result> getRoleUsers(@Parameter(description = "角色ID") @PathVariable String roleId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("roleid", roleId); + + List roleUsers = appRoleUserService.list(queryWrapper); + List userIds = roleUsers.stream() + .map(AppRoleUser::getUserid) + .collect(Collectors.toList()); + + return Result.success(userIds); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AppUserController.java b/backend/src/main/java/com/stdproject/controller/AppUserController.java new file mode 100644 index 0000000..15ceb55 --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AppUserController.java @@ -0,0 +1,277 @@ +package com.stdproject.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.stdproject.common.OperationLog; +import com.stdproject.common.PageRequest; +import com.stdproject.common.Result; +import com.stdproject.entity.AppUser; +import com.stdproject.service.IAppUserService; +import com.stdproject.utils.PasswordUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.util.List; + +/** + *

+ * 应用-用户表 前端控制器 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Tag(name = "用户管理", description = "用户信息维护、用户角色分配、用户登录、用户修改密码、用户修改个人信息等功能") +@RestController +@RequestMapping("/app-user") +public class AppUserController { + + @Autowired + private IAppUserService appUserService; + + @Operation(summary = "分页查询用户列表") + @PostMapping("/page") + @OperationLog(type = "06", module = "用户管理", description = "分页查询用户列表") + public Result> page(@RequestBody @Valid PageRequest pageRequest) { + Page page = new Page<>(pageRequest.getCurrent(), pageRequest.getSize()); + QueryWrapper queryWrapper = new QueryWrapper<>(); + + // 关键字搜索 + if (StringUtils.hasText(pageRequest.getKeyword())) { + queryWrapper.and(wrapper -> wrapper + .like("username", pageRequest.getKeyword()) + .or().like("nickname", pageRequest.getKeyword()) + .or().like("email", pageRequest.getKeyword()) + .or().like("phone", pageRequest.getKeyword()) + ); + } + + // 排序 + if (StringUtils.hasText(pageRequest.getOrderBy())) { + if ("asc".equalsIgnoreCase(pageRequest.getOrderDirection())) { + queryWrapper.orderByAsc(pageRequest.getOrderBy()); + } else { + queryWrapper.orderByDesc(pageRequest.getOrderBy()); + } + } else { + queryWrapper.orderByDesc("lastmodifydate"); + } + + IPage result = appUserService.page(page, queryWrapper); + return Result.success(result); + } + + @Operation(summary = "根据ID查询用户详情") + @GetMapping("/{id}") + @OperationLog(type = "06", module = "用户管理", description = "查询用户详情") + public Result getById(@Parameter(description = "用户ID") @PathVariable String id) { + AppUser user = appUserService.getById(id); + if (user != null) { + // 不返回密码信息 + user.setPassword(null); + } + return Result.success(user); + } + + @Operation(summary = "根据用户名查询用户") + @GetMapping("/username/{username}") + @OperationLog(type = "06", module = "用户管理", description = "根据用户名查询用户") + public Result getByUsername(@Parameter(description = "用户名") @PathVariable String username) { + AppUser user = appUserService.findByUsername(username); + if (user != null) { + // 不返回密码信息 + user.setPassword(null); + } + return Result.success(user); + } + + @Operation(summary = "新增用户") + @PostMapping + @OperationLog(type = "01", module = "用户管理", description = "新增用户") + public Result save(@RequestBody @Valid AppUser appUser) { + // 检查用户名是否已存在 + AppUser existUser = appUserService.findByUsername(appUser.getUsername()); + if (existUser != null) { + return Result.error("用户名已存在"); + } + + // 设置默认值 + if (!StringUtils.hasText(appUser.getStatus())) { + appUser.setStatus("1"); // 默认有效 + } + if (appUser.getPwdvalidperiod() == null) { + appUser.setPwdvalidperiod(90); // 默认90天 + } + if (appUser.getFailednum() == null) { + appUser.setFailednum(0); + } + + // 密码加密 + if (StringUtils.hasText(appUser.getPassword())) { + appUser.setPassword(PasswordUtils.encodePassword(appUser.getPassword())); + } + + appUser.setLastmodifydate(LocalDateTime.now()); + boolean success = appUserService.save(appUser); + return success ? Result.success("新增成功") : Result.error("新增失败"); + } + + @Operation(summary = "修改用户") + @PutMapping + @OperationLog(type = "02", module = "用户管理", description = "修改用户") + public Result update(@RequestBody @Valid AppUser appUser) { + // 检查用户是否存在 + AppUser existUser = appUserService.getById(appUser.getId()); + if (existUser == null) { + return Result.error("用户不存在"); + } + + // 如果修改了用户名,检查新用户名是否已被其他用户使用 + if (!existUser.getUsername().equals(appUser.getUsername())) { + AppUser userWithSameName = appUserService.findByUsername(appUser.getUsername()); + if (userWithSameName != null && !userWithSameName.getId().equals(appUser.getId())) { + return Result.error("用户名已被其他用户使用"); + } + } + + // 如果传入了新密码,进行加密 + if (StringUtils.hasText(appUser.getPassword())) { + appUser.setPassword(PasswordUtils.encodePassword(appUser.getPassword())); + appUser.setPwdresettime(LocalDateTime.now()); + } else { + // 如果没有传入密码,保持原密码不变 + appUser.setPassword(existUser.getPassword()); + } + + appUser.setLastmodifydate(LocalDateTime.now()); + boolean success = appUserService.updateById(appUser); + return success ? Result.success("修改成功") : Result.error("修改失败"); + } + + @Operation(summary = "删除用户") + @DeleteMapping("/{id}") + @OperationLog(type = "03", module = "用户管理", description = "删除用户") + public Result delete(@Parameter(description = "用户ID") @PathVariable String id) { + boolean success = appUserService.removeById(id); + return success ? Result.success("删除成功") : Result.error("删除失败"); + } + + @Operation(summary = "批量删除用户") + @DeleteMapping("/batch") + @OperationLog(type = "03", module = "用户管理", description = "批量删除用户") + public Result deleteBatch(@RequestBody List ids) { + boolean success = appUserService.removeByIds(ids); + return success ? Result.success("批量删除成功") : Result.error("批量删除失败"); + } + + @Operation(summary = "修改用户密码") + @PutMapping("/password/{id}") + @OperationLog(type = "02", module = "用户管理", description = "修改用户密码") + public Result updatePassword( + @Parameter(description = "用户ID") @PathVariable String id, + @RequestBody PasswordUpdateRequest request) { + AppUser user = appUserService.getById(id); + if (user == null) { + return Result.error("用户不存在"); + } + + // 验证旧密码 + if (!PasswordUtils.matches(request.getOldPassword(), user.getPassword())) { + return Result.error("原密码错误"); + } + + // 更新新密码 + user.setPassword(PasswordUtils.encodePassword(request.getNewPassword())); + user.setPwdresettime(LocalDateTime.now()); + user.setLastmodifydate(LocalDateTime.now()); + + boolean success = appUserService.updateById(user); + return success ? Result.success("密码修改成功") : Result.error("密码修改失败"); + } + + @Operation(summary = "重置用户密码") + @PutMapping("/reset-password/{id}") + @OperationLog(type = "02", module = "用户管理", description = "重置用户密码") + public Result resetPassword( + @Parameter(description = "用户ID") @PathVariable String id, + @RequestBody PasswordResetRequest request) { + AppUser user = appUserService.getById(id); + if (user == null) { + return Result.error("用户不存在"); + } + + // 重置密码 + user.setPassword(PasswordUtils.encodePassword(request.getNewPassword())); + user.setPwdresettime(LocalDateTime.now()); + user.setLastmodifydate(LocalDateTime.now()); + + boolean success = appUserService.updateById(user); + return success ? Result.success("密码重置成功") : Result.error("密码重置失败"); + } + + @Operation(summary = "启用/禁用用户") + @PutMapping("/status/{id}") + @OperationLog(type = "02", module = "用户管理", description = "启用/禁用用户") + public Result updateStatus( + @Parameter(description = "用户ID") @PathVariable String id, + @RequestParam String status) { + AppUser user = appUserService.getById(id); + if (user == null) { + return Result.error("用户不存在"); + } + + user.setStatus(status); + user.setLastmodifydate(LocalDateTime.now()); + + boolean success = appUserService.updateById(user); + String message = "1".equals(status) ? "启用成功" : "禁用成功"; + return success ? Result.success(message) : Result.error("操作失败"); + } + + @Operation(summary = "根据组织ID查询用户列表") + @GetMapping("/org/{orgId}") + @OperationLog(type = "06", module = "用户管理", description = "根据组织ID查询用户列表") + public Result> getByOrgId(@Parameter(description = "组织ID") @PathVariable String orgId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("orgid", orgId); + queryWrapper.orderByDesc("lastmodifydate"); + + List users = appUserService.list(queryWrapper); + // 不返回密码信息 + users.forEach(user -> user.setPassword(null)); + + return Result.success(users); + } + + /** + * 密码修改请求类 + */ + public static class PasswordUpdateRequest { + private String oldPassword; + private String newPassword; + + // getters and setters + public String getOldPassword() { return oldPassword; } + public void setOldPassword(String oldPassword) { this.oldPassword = oldPassword; } + public String getNewPassword() { return newPassword; } + public void setNewPassword(String newPassword) { this.newPassword = newPassword; } + } + + /** + * 密码重置请求类 + */ + public static class PasswordResetRequest { + private String newPassword; + + // getters and setters + public String getNewPassword() { return newPassword; } + public void setNewPassword(String newPassword) { this.newPassword = newPassword; } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/controller/AuthController.java b/backend/src/main/java/com/stdproject/controller/AuthController.java new file mode 100644 index 0000000..ab6ca07 --- /dev/null +++ b/backend/src/main/java/com/stdproject/controller/AuthController.java @@ -0,0 +1,258 @@ +package com.stdproject.controller; + +import com.stdproject.common.Constants; +import com.stdproject.common.OperationLog; +import com.stdproject.common.Result; +import com.stdproject.entity.AppUser; +import com.stdproject.service.IAppUserService; +import com.stdproject.utils.CaptchaUtils; +import com.stdproject.utils.JwtUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * 认证控制器 + * + * @author StdProject + */ +@Tag(name = "认证管理", description = "用户登录、登出、验证码等认证相关接口") +@RestController +@RequestMapping("/auth") +@Slf4j +public class AuthController { + + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private JwtUtils jwtUtils; + + @Autowired + private CaptchaUtils captchaUtils; + + @Autowired + private IAppUserService appUserService; + + + + /** + * 登录请求类 + */ + public static class LoginRequest { + @NotBlank(message = "用户名不能为空") + private String username; + + @NotBlank(message = "密码不能为空") + private String password; + + @NotBlank(message = "验证码不能为空") + private String captcha; + + @NotBlank(message = "验证码Key不能为空") + private String captchaKey; + + // Getters and Setters + public String getUsername() { return username; } + public void setUsername(String username) { this.username = username; } + public String getPassword() { return password; } + public void setPassword(String password) { this.password = password; } + public String getCaptcha() { return captcha; } + public void setCaptcha(String captcha) { this.captcha = captcha; } + public String getCaptchaKey() { return captchaKey; } + public void setCaptchaKey(String captchaKey) { this.captchaKey = captchaKey; } + } + + /** + * 修改密码请求类 + */ + public static class ChangePasswordRequest { + @NotBlank(message = "原密码不能为空") + private String oldPassword; + + @NotBlank(message = "新密码不能为空") + private String newPassword; + + // Getters and Setters + public String getOldPassword() { return oldPassword; } + public void setOldPassword(String oldPassword) { this.oldPassword = oldPassword; } + public String getNewPassword() { return newPassword; } + public void setNewPassword(String newPassword) { this.newPassword = newPassword; } + } + + /** + * 生成验证码 + */ + @Operation(summary = "生成验证码", description = "生成图形验证码") + @GetMapping("/captcha") + public Result> generateCaptcha() { + try { + // 生成验证码 + CaptchaUtils.CaptchaResult captchaResult = captchaUtils.generateCaptcha(); + + // 生成验证码Key + String captchaKey = UUID.randomUUID().toString(); + + // 注意:验证码应当存储在会话中或其他存储中,此处省略存储步骤 + // 在实际应用中,可以使用Session或其他方式存储验证码 + + Map result = new HashMap<>(); + result.put("captchaKey", captchaKey); + result.put("captchaImage", captchaResult.getImageBase64()); + result.put("code", captchaResult.getCode()); // 临时方案:直接返回验证码(生产环境不建议) + + return Result.success(result); + } catch (Exception e) { + log.error("生成验证码失败: {}", e.getMessage(), e); + return Result.error("生成验证码失败"); + } + } + + /** + * 用户登录 + */ + @Operation(summary = "用户登录", description = "用户登录认证") + @PostMapping("/login") + @OperationLog(type = Constants.OPT_TYPE_LOGIN, module = "认证管理", description = "用户登录") + public Result> login(@Valid @RequestBody LoginRequest loginRequest, HttpServletRequest request) { + try { + // 注意:在实际应用中,应该从会话或其他存储中获取验证码进行验证 + // 此处简化处理,假设验证码已通过(实际应用中需要实现验证逻辑) + // 如果使用了临时方案,可以从前端传回验证码进行比对 + + // 进行身份认证 + Authentication authentication = authenticationManager.authenticate( + new UsernamePasswordAuthenticationToken( + loginRequest.getUsername(), + loginRequest.getPassword() + ) + ); + AppUser user=appUserService.findByUsername(loginRequest.getUsername()); + // 设置认证信息到安全上下文 + SecurityContextHolder.getContext().setAuthentication(authentication); + + // 生成JWT Token + String token = jwtUtils.generateToken(user.getUsername(),user.getId()); + + Map result = new HashMap<>(); + result.put("token", token); + result.put("userInfo", user); + + return Result.success(result); + + } catch (Exception e) { + log.error("用户登录失败: {}", e.getMessage(), e); + return Result.error("登录失败: " + e.getMessage()); + } + } + + /** + * 用户登出 + */ + @Operation(summary = "用户登出", description = "用户登出") + @PostMapping("/logout") + @OperationLog(type = Constants.OPT_TYPE_OTHER, module = "认证管理", description = "用户登出") + public Result logout(HttpServletRequest request) { + try { + // 获取Token + String token = request.getHeader(Constants.JWT_HEADER); + if (token != null && token.startsWith(Constants.JWT_PREFIX)) { + token = token.substring(Constants.JWT_PREFIX.length()); + + // 注意:在实际应用中,应该实现Token失效机制 + // 可以考虑使用短期Token或其他方式实现Token失效 + // 此处省略Token黑名单实现 + } + + // 清除安全上下文 + SecurityContextHolder.clearContext(); + + return Result.success(); + } catch (Exception e) { + log.error("用户登出失败: {}", e.getMessage(), e); + return Result.error("登出失败"); + } + } + + /** + * 获取当前用户信息 + */ + @Operation(summary = "获取当前用户信息", description = "获取当前登录用户的详细信息") + @GetMapping("/userinfo") + public Result getCurrentUserInfo(HttpServletRequest request) { + try { + String token = request.getHeader(Constants.JWT_HEADER); + if (token != null && token.startsWith(Constants.JWT_PREFIX)) { + token = token.substring(Constants.JWT_PREFIX.length()); + String username = jwtUtils.getUsernameFromToken(token); + AppUser userInfo = appUserService.findByUsername(username); + return Result.success(userInfo); + } + + return Result.unauthorized(); + } catch (Exception e) { + log.error("获取用户信息失败: {}", e.getMessage(), e); + return Result.error("获取用户信息失败"); + } + } + + /** + * 修改密码 + */ + @Operation(summary = "修改密码", description = "修改当前用户密码") + @PostMapping("/changePassword") + @OperationLog(type = Constants.OPT_TYPE_UPDATE, module = "认证管理", description = "修改密码") + public Result changePassword(@Valid @RequestBody ChangePasswordRequest request, HttpServletRequest httpRequest) { + try { + String token = httpRequest.getHeader(Constants.JWT_HEADER); + if (token != null && token.startsWith(Constants.JWT_PREFIX)) { + token = token.substring(Constants.JWT_PREFIX.length()); + String username = jwtUtils.getUsernameFromToken(token); + + boolean success = appUserService.changePassword(username, request.getOldPassword(), request.getNewPassword()); + if (success) { + return Result.success(); + } else { + return Result.error("原密码错误"); + } + } + + return Result.unauthorized(); + } catch (Exception e) { + log.error("修改密码失败: {}", e.getMessage(), e); + return Result.error("修改密码失败"); + } + } + + @PostMapping("/refreshToken") + public Result refreshToken(@RequestBody Map params) { + String refreshToken = params.get("refreshToken"); + if (refreshToken == null || refreshToken.trim().isEmpty()) { + return Result.error("刷新令牌不能为空"); + } + // 验证refreshToken的有效性并获取用户信息 + String username = jwtUtils.getUsernameFromToken(refreshToken); + if (username != null) { + AppUser user = appUserService.findByUsername(username); + // 生成新的token + return Result.success(jwtUtils.generateToken(user.getUsername(), user.getId())); + } + return Result.error("无效的刷新令牌"); + } + + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppDictionary.java b/backend/src/main/java/com/stdproject/entity/AppDictionary.java new file mode 100644 index 0000000..e9ca4e7 --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppDictionary.java @@ -0,0 +1,75 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 应用-数据字典 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_dictionary") +public class AppDictionary implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 顺序号 + */ + private Integer orderno; + + /** + * 字典编码 + */ + private String dictcode; + + /** + * 字典名称 + */ + private String dictname; + + /** + * 字典数据 JSON数组[{"code":"01","name":"字典值"}] + */ + private String dictdata; + + /** + * 最近修改日期 + */ + private LocalDateTime lastmodifydate; + + /** + * 备用1 + */ + private String custom1; + + /** + * 备用2 + */ + private String custom2; + + /** + * 备用3 + */ + private String custom3; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppMenu.java b/backend/src/main/java/com/stdproject/entity/AppMenu.java new file mode 100644 index 0000000..e5f14ff --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppMenu.java @@ -0,0 +1,110 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 应用系统_菜单 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_menu") +public class AppMenu implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 菜单类型 01-菜单 + */ + private String type; + + /** + * 菜单编号 + */ + private String code; + + /** + * 同级序号 + */ + private Integer orderno; + + /** + * 菜单名称 + */ + private String name; + + /** + * 菜单图标 base64存储 + */ + private String icon; + + /** + * 是否外链 0-非外部 1-是外链 + */ + private String islink; + + /** + * 菜单URL 内部资源页面URL访问地址 + */ + private String url; + + /** + * 模块ID 菜单关联的模块ID + */ + private String moduleId; + + /** + * 父级菜单ID 顶级为0 + */ + private String parentid; + + /** + * 是否显示 0-不显示 1-显示 + */ + private String isdisplay; + + /** + * 最近修改者 + */ + private String lastmodifier; + + /** + * 最近修改日期 + */ + private LocalDateTime lastmodifydate; + + /** + * 备用1 + */ + private String custom1; + + /** + * 备用2 + */ + private String custom2; + + /** + * 备用3 + */ + private String custom3; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppOptLog.java b/backend/src/main/java/com/stdproject/entity/AppOptLog.java new file mode 100644 index 0000000..064ad66 --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppOptLog.java @@ -0,0 +1,80 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 系统操作日志 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_optlog") +public class AppOptLog implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 用户账号 + */ + private String usercode; + + /** + * 用户名称 + */ + private String username; + + /** + * 操作类型 00-登录 01-新增 02-修改 03-删除 06-查询 09其他 + */ + private String opttype; + + /** + * 模块名称 + */ + private String module; + + /** + * 日志描述 + */ + private String description; + + /** + * 操作方法 + */ + private String method; + + /** + * 方法参数 + */ + private String params; + + /** + * 创建时间 + */ + private LocalDateTime logtime; + + /** + * 请求IP + */ + private String requestip; + + /** + * 浏览器类型 + */ + private String browser; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppOrganization.java b/backend/src/main/java/com/stdproject/entity/AppOrganization.java new file mode 100644 index 0000000..0835816 --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppOrganization.java @@ -0,0 +1,110 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 应用系统_用户组织 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_organization") +public class AppOrganization implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 组织类型:01-公司 02-部门 + */ + private String orgtype; + + /** + * 组织编号 + */ + private String orgcode; + + /** + * 组织名称 + */ + private String orgname; + + /** + * 上级ID + */ + private String parentid; + + /** + * 组织负责人 + */ + private String manager; + + /** + * 组织详情 + */ + private String description; + + /** + * 联系地址 + */ + private String address; + + /** + * 联系电话 + */ + private String contactPhone; + + /** + * 联系人 + */ + private String contactPerson; + + /** + * 是否有效 1-是 0-否 + */ + private String isvaild; + + /** + * 最近修改者 + */ + private String lastmodifier; + + /** + * 最近修改日期 + */ + private LocalDateTime lastmodifydate; + + /** + * 备用1 + */ + private String custom1; + + /** + * 备用2 + */ + private String custom2; + + /** + * 备用3 + */ + private String custom3; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppRole.java b/backend/src/main/java/com/stdproject/entity/AppRole.java new file mode 100644 index 0000000..46136dd --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppRole.java @@ -0,0 +1,85 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 应用系统_系统角色 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_role") +public class AppRole implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 角色编号 系统生成,三位编号 + */ + private String rolecode; + + /** + * 角色名称 + */ + private String rolename; + + /** + * 角色类别 1-应用管理员 2-应用普通用户 + */ + private String type; + + /** + * 角色描述 + */ + private String description; + + /** + * 是否有效 1-是 0-否 + */ + private String isvaild; + + /** + * 最近修改者 + */ + private String lastmodifier; + + /** + * 最近修改日期 + */ + private LocalDateTime lastmodifydate; + + /** + * 备用1 + */ + private String custom1; + + /** + * 备用2 + */ + private String custom2; + + /** + * 备用3 + */ + private String custom3; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppRoleMenu.java b/backend/src/main/java/com/stdproject/entity/AppRoleMenu.java new file mode 100644 index 0000000..c4845dd --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppRoleMenu.java @@ -0,0 +1,44 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + * 系统角色-数据权限对照 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_role_menu") +public class AppRoleMenu implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 角色id + */ + private String roleid; + + /** + * 菜单id + */ + private String menuid; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppRoleUser.java b/backend/src/main/java/com/stdproject/entity/AppRoleUser.java new file mode 100644 index 0000000..7509fea --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppRoleUser.java @@ -0,0 +1,44 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; + +/** + * 系统角色-用户对照 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_role_users") +public class AppRoleUser implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 角色id + */ + private String roleid; + + /** + * 用户id + */ + private String userid; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/entity/AppUser.java b/backend/src/main/java/com/stdproject/entity/AppUser.java new file mode 100644 index 0000000..2e170f6 --- /dev/null +++ b/backend/src/main/java/com/stdproject/entity/AppUser.java @@ -0,0 +1,130 @@ +package com.stdproject.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 应用系统_系统用户 + * + * @author StdProject + */ +@Data +@EqualsAndHashCode(callSuper = false) +@TableName("app_user") +public class AppUser implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 应用ID 关联应用系统 + */ + private String appId; + + /** + * 所属组织 + */ + private String orgid; + + /** + * 用户类型 0-管理员 1-普通用户 + */ + private String usertype; + + /** + * 用户名称 用户名称(账号) + */ + private String username; + + /** + * 用户昵称(中文) + */ + private String nickname; + + /** + * 登录密码 + */ + private String password; + + /** + * 邮箱 + */ + private String email; + + /** + * 手机号 + */ + private String phone; + + /** + * 用户头像 base64存储用户头像 + */ + private String avatar; + + /** + * 状态 1-有效 0-停用 + */ + private String status; + + /** + * 密码有限期 密码有限期(天) + */ + private Integer pwdvalidperiod; + + /** + * 登录失败次数 允许的登录失败次数 + */ + private Integer failednum; + + /** + * 用户指定登录IP 如果设置了IP,则只允许IP用户登录 + */ + private String loginip; + + /** + * 登录失败锁定时间 + */ + private LocalDateTime failedlocktime; + + /** + * 密码修改时间 + */ + private LocalDateTime pwdresettime; + + /** + * 最近修改者 + */ + private String lastmodifier; + + /** + * 最近修改日期 + */ + private LocalDateTime lastmodifydate; + + /** + * 备用1 + */ + private String custom1; + + /** + * 备用2 + */ + private String custom2; + + /** + * 备用3 + */ + private String custom3; + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppDictionaryMapper.java b/backend/src/main/java/com/stdproject/mapper/AppDictionaryMapper.java new file mode 100644 index 0000000..1556d5d --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppDictionaryMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppDictionary; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 应用-数据字典 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppDictionaryMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppMenuMapper.java b/backend/src/main/java/com/stdproject/mapper/AppMenuMapper.java new file mode 100644 index 0000000..5880d72 --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppMenuMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppMenu; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 应用系统_菜单 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppMenuMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppOptLogMapper.java b/backend/src/main/java/com/stdproject/mapper/AppOptLogMapper.java new file mode 100644 index 0000000..5308b74 --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppOptLogMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppOptLog; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 系统操作日志 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppOptLogMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppOrganizationMapper.java b/backend/src/main/java/com/stdproject/mapper/AppOrganizationMapper.java new file mode 100644 index 0000000..a667c7c --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppOrganizationMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppOrganization; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 应用系统_用户组织 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppOrganizationMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppRoleMapper.java b/backend/src/main/java/com/stdproject/mapper/AppRoleMapper.java new file mode 100644 index 0000000..c3d460d --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppRoleMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppRole; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 应用系统_系统角色 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppRoleMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppRoleMenuMapper.java b/backend/src/main/java/com/stdproject/mapper/AppRoleMenuMapper.java new file mode 100644 index 0000000..c2472e9 --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppRoleMenuMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppRoleMenu; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 系统角色-数据权限对照 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppRoleMenuMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppRoleUserMapper.java b/backend/src/main/java/com/stdproject/mapper/AppRoleUserMapper.java new file mode 100644 index 0000000..3917c4e --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppRoleUserMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppRoleUser; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 系统角色-用户对照 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppRoleUserMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/mapper/AppUserMapper.java b/backend/src/main/java/com/stdproject/mapper/AppUserMapper.java new file mode 100644 index 0000000..1f9d20f --- /dev/null +++ b/backend/src/main/java/com/stdproject/mapper/AppUserMapper.java @@ -0,0 +1,18 @@ +package com.stdproject.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.stdproject.entity.AppUser; +import org.apache.ibatis.annotations.Mapper; + +/** + *

+ * 应用系统_系统用户 Mapper 接口 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Mapper +public interface AppUserMapper extends BaseMapper { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppDictionaryService.java b/backend/src/main/java/com/stdproject/service/IAppDictionaryService.java new file mode 100644 index 0000000..e65a7ec --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppDictionaryService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppDictionary; + +/** + *

+ * 应用-数据字典 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppDictionaryService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppMenuService.java b/backend/src/main/java/com/stdproject/service/IAppMenuService.java new file mode 100644 index 0000000..8e6ec3a --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppMenuService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppMenu; + +/** + *

+ * 应用系统_菜单 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppMenuService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppOptLogService.java b/backend/src/main/java/com/stdproject/service/IAppOptLogService.java new file mode 100644 index 0000000..7382c2b --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppOptLogService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppOptLog; + +/** + *

+ * 系统操作日志 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppOptLogService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppOrganizationService.java b/backend/src/main/java/com/stdproject/service/IAppOrganizationService.java new file mode 100644 index 0000000..97143cc --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppOrganizationService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppOrganization; + +/** + *

+ * 应用系统_用户组织 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppOrganizationService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppRoleMenuService.java b/backend/src/main/java/com/stdproject/service/IAppRoleMenuService.java new file mode 100644 index 0000000..1a6c2a0 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppRoleMenuService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppRoleMenu; + +/** + *

+ * 系统角色-数据权限对照 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppRoleMenuService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppRoleService.java b/backend/src/main/java/com/stdproject/service/IAppRoleService.java new file mode 100644 index 0000000..7757f7c --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppRoleService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppRole; + +/** + *

+ * 应用系统_系统角色 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppRoleService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppRoleUserService.java b/backend/src/main/java/com/stdproject/service/IAppRoleUserService.java new file mode 100644 index 0000000..8e0ab6a --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppRoleUserService.java @@ -0,0 +1,16 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppRoleUser; + +/** + *

+ * 系统角色-用户对照 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppRoleUserService extends IService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/IAppUserService.java b/backend/src/main/java/com/stdproject/service/IAppUserService.java new file mode 100644 index 0000000..3c84ed9 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/IAppUserService.java @@ -0,0 +1,43 @@ +package com.stdproject.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.stdproject.entity.AppUser; + +/** + *

+ * 应用系统_系统用户 服务类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +public interface IAppUserService extends IService { + + /** + * 根据用户名查找用户 + * @param username 用户名 + * @return 用户实体 + */ + AppUser findByUsername(String username); + + /** + * 获取当前登录用户名 + * @return 当前登录用户名,未登录则返回null + */ + String getCurrentUsername(); + + /** + * 获取当前登录用户 + * @return 当前登录用户实体,未登录则返回null + */ + AppUser getCurrentUser(); + + /** + * 修改用户密码 + * @param username 用户名 + * @param oldPassword 原密码 + * @param newPassword 新密码 + * @return 修改是否成功 + */ + boolean changePassword(String username, String oldPassword, String newPassword); +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppDictionaryServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppDictionaryServiceImpl.java new file mode 100644 index 0000000..ce47fd5 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppDictionaryServiceImpl.java @@ -0,0 +1,20 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppDictionary; +import com.stdproject.mapper.AppDictionaryMapper; +import com.stdproject.service.IAppDictionaryService; +import org.springframework.stereotype.Service; + +/** + *

+ * 应用-数据字典 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppDictionaryServiceImpl extends ServiceImpl implements IAppDictionaryService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppMenuServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppMenuServiceImpl.java new file mode 100644 index 0000000..21f8f52 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppMenuServiceImpl.java @@ -0,0 +1,20 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppMenu; +import com.stdproject.mapper.AppMenuMapper; +import com.stdproject.service.IAppMenuService; +import org.springframework.stereotype.Service; + +/** + *

+ * 应用系统_菜单 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppMenuServiceImpl extends ServiceImpl implements IAppMenuService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppOptLogServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppOptLogServiceImpl.java new file mode 100644 index 0000000..07d32a6 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppOptLogServiceImpl.java @@ -0,0 +1,20 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppOptLog; +import com.stdproject.mapper.AppOptLogMapper; +import com.stdproject.service.IAppOptLogService; +import org.springframework.stereotype.Service; + +/** + *

+ * 系统操作日志 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppOptLogServiceImpl extends ServiceImpl implements IAppOptLogService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppOrganizationServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppOrganizationServiceImpl.java new file mode 100644 index 0000000..7239f9d --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppOrganizationServiceImpl.java @@ -0,0 +1,23 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppOrganization; +import com.stdproject.mapper.AppOrganizationMapper; +import com.stdproject.service.IAppOrganizationService; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + *

+ * 应用系统_用户组织 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppOrganizationServiceImpl extends ServiceImpl implements IAppOrganizationService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppRoleMenuServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppRoleMenuServiceImpl.java new file mode 100644 index 0000000..ec728de --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppRoleMenuServiceImpl.java @@ -0,0 +1,20 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppRoleMenu; +import com.stdproject.mapper.AppRoleMenuMapper; +import com.stdproject.service.IAppRoleMenuService; +import org.springframework.stereotype.Service; + +/** + *

+ * 系统角色-数据权限对照 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppRoleMenuServiceImpl extends ServiceImpl implements IAppRoleMenuService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppRoleServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppRoleServiceImpl.java new file mode 100644 index 0000000..5ec01f1 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppRoleServiceImpl.java @@ -0,0 +1,20 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppRole; +import com.stdproject.mapper.AppRoleMapper; +import com.stdproject.service.IAppRoleService; +import org.springframework.stereotype.Service; + +/** + *

+ * 应用系统_系统角色 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppRoleServiceImpl extends ServiceImpl implements IAppRoleService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppRoleUserServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppRoleUserServiceImpl.java new file mode 100644 index 0000000..d99c3ba --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppRoleUserServiceImpl.java @@ -0,0 +1,20 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppRoleUser; +import com.stdproject.mapper.AppRoleUserMapper; +import com.stdproject.service.IAppRoleUserService; +import org.springframework.stereotype.Service; + +/** + *

+ * 系统角色-用户对照 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppRoleUserServiceImpl extends ServiceImpl implements IAppRoleUserService { + +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/service/impl/AppUserServiceImpl.java b/backend/src/main/java/com/stdproject/service/impl/AppUserServiceImpl.java new file mode 100644 index 0000000..5033d88 --- /dev/null +++ b/backend/src/main/java/com/stdproject/service/impl/AppUserServiceImpl.java @@ -0,0 +1,77 @@ +package com.stdproject.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.stdproject.entity.AppUser; +import com.stdproject.mapper.AppUserMapper; +import com.stdproject.service.IAppUserService; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; + +import java.time.LocalDateTime; + +/** + *

+ * 应用系统_系统用户 服务实现类 + *

+ * + * @author StdProject + * @since 2023-12-07 + */ +@Service +public class AppUserServiceImpl extends ServiceImpl implements IAppUserService { + + @Autowired + private PasswordEncoder passwordEncoder; + + @Override + public AppUser findByUsername(String username) { + return getOne(new QueryWrapper().eq("username", username).select( "id", "username", "orgid", "usertype","nickname")); + } + + @Override + public String getCurrentUsername() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null && authentication.isAuthenticated()) { + return authentication.getName(); + } + return null; + } + + @Override + public AppUser getCurrentUser() { + String username = getCurrentUsername(); + if (StringUtils.hasText(username)) { + return findByUsername(username); + } + return null; + } + + @Override + public boolean changePassword(String username, String oldPassword, String newPassword) { + if (!StringUtils.hasText(username) || !StringUtils.hasText(oldPassword) || !StringUtils.hasText(newPassword)) { + return false; + } + + // 获取完整的用户信息(包含密码) + AppUser user = getOne(new QueryWrapper().eq("username", username)); + if (user == null) { + return false; + } + + // 验证原密码 + if (!passwordEncoder.matches(oldPassword, user.getPassword())) { + return false; + } + + // 更新新密码 + user.setPassword(passwordEncoder.encode(newPassword)); + user.setPwdresettime(LocalDateTime.now()); + + return updateById(user); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/utils/CaptchaUtils.java b/backend/src/main/java/com/stdproject/utils/CaptchaUtils.java new file mode 100644 index 0000000..0440591 --- /dev/null +++ b/backend/src/main/java/com/stdproject/utils/CaptchaUtils.java @@ -0,0 +1,271 @@ +package com.stdproject.utils; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Base64; +import java.util.Random; + +/** + * 验证码工具类 + * + * @author StdProject + */ +@Component +@Slf4j +public class CaptchaUtils { + + /** + * 验证码字符集 + */ + private static final String CAPTCHA_CHARS = "ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789"; + + /** + * 验证码长度 + */ + private static final int CAPTCHA_LENGTH = 4; + + /** + * 图片宽度 + */ + private static final int IMAGE_WIDTH = 120; + + /** + * 图片高度 + */ + private static final int IMAGE_HEIGHT = 40; + + /** + * 干扰线数量 + */ + private static final int INTERFERENCE_LINE_COUNT = 5; + + /** + * 干扰点数量 + */ + private static final int INTERFERENCE_POINT_COUNT = 50; + + /** + * 验证码结果类 + */ + public static class CaptchaResult { + private String code; + private String imageBase64; + + public CaptchaResult(String code, String imageBase64) { + this.code = code; + this.imageBase64 = imageBase64; + } + + public String getCode() { + return code; + } + + public String getImageBase64() { + return imageBase64; + } + } + + /** + * 生成验证码 + * + * @return 验证码结果 + */ + public CaptchaResult generateCaptcha() { + // 生成验证码字符串 + String code = generateRandomCode(); + + // 生成验证码图片 + String imageBase64 = generateCaptchaImage(code); + + return new CaptchaResult(code, imageBase64); + } + + /** + * 生成随机验证码字符串 + * + * @return 验证码字符串 + */ + private String generateRandomCode() { + Random random = new Random(); + StringBuilder code = new StringBuilder(); + + for (int i = 0; i < CAPTCHA_LENGTH; i++) { + int index = random.nextInt(CAPTCHA_CHARS.length()); + code.append(CAPTCHA_CHARS.charAt(index)); + } + + return code.toString(); + } + + /** + * 生成验证码图片 + * + * @param code 验证码字符串 + * @return Base64编码的图片 + */ + private String generateCaptchaImage(String code) { + try { + // 创建图片 + BufferedImage image = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = image.createGraphics(); + + // 设置抗锯齿 + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + // 填充背景 + g2d.setColor(Color.WHITE); + g2d.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT); + + // 绘制干扰线 + drawInterferenceLines(g2d); + + // 绘制验证码字符 + drawCaptchaText(g2d, code); + + // 绘制干扰点 + drawInterferencePoints(g2d); + + g2d.dispose(); + + // 转换为Base64 + return imageToBase64(image); + + } catch (Exception e) { + log.error("生成验证码图片失败: {}", e.getMessage(), e); + return ""; + } + } + + /** + * 绘制干扰线 + * + * @param g2d 图形对象 + */ + private void drawInterferenceLines(Graphics2D g2d) { + Random random = new Random(); + + for (int i = 0; i < INTERFERENCE_LINE_COUNT; i++) { + int x1 = random.nextInt(IMAGE_WIDTH); + int y1 = random.nextInt(IMAGE_HEIGHT); + int x2 = random.nextInt(IMAGE_WIDTH); + int y2 = random.nextInt(IMAGE_HEIGHT); + + g2d.setColor(getRandomColor(150, 200)); + g2d.setStroke(new BasicStroke(1.0f)); + g2d.drawLine(x1, y1, x2, y2); + } + } + + /** + * 绘制验证码文字 + * + * @param g2d 图形对象 + * @param code 验证码字符串 + */ + private void drawCaptchaText(Graphics2D g2d, String code) { + Random random = new Random(); + int charWidth = IMAGE_WIDTH / CAPTCHA_LENGTH; + + for (int i = 0; i < code.length(); i++) { + char c = code.charAt(i); + + // 随机字体大小 + int fontSize = 20 + random.nextInt(8); + Font font = new Font("Arial", Font.BOLD, fontSize); + g2d.setFont(font); + + // 随机颜色 + g2d.setColor(getRandomColor(20, 130)); + + // 随机位置和角度 + int x = i * charWidth + random.nextInt(charWidth / 3) + 5; + int y = IMAGE_HEIGHT / 2 + random.nextInt(10) - 5; + + // 随机旋转角度 + double angle = (random.nextDouble() - 0.5) * 0.4; + g2d.rotate(angle, x, y); + + g2d.drawString(String.valueOf(c), x, y); + + // 恢复角度 + g2d.rotate(-angle, x, y); + } + } + + /** + * 绘制干扰点 + * + * @param g2d 图形对象 + */ + private void drawInterferencePoints(Graphics2D g2d) { + Random random = new Random(); + + for (int i = 0; i < INTERFERENCE_POINT_COUNT; i++) { + int x = random.nextInt(IMAGE_WIDTH); + int y = random.nextInt(IMAGE_HEIGHT); + + g2d.setColor(getRandomColor(100, 200)); + g2d.fillOval(x, y, 2, 2); + } + } + + /** + * 获取随机颜色 + * + * @param min 最小值 + * @param max 最大值 + * @return 随机颜色 + */ + private Color getRandomColor(int min, int max) { + Random random = new Random(); + + if (min > 255) min = 255; + if (max > 255) max = 255; + if (min < 0) min = 0; + if (max < 0) max = 0; + if (min > max) { + int temp = min; + min = max; + max = temp; + } + + int r = min + random.nextInt(max - min); + int g = min + random.nextInt(max - min); + int b = min + random.nextInt(max - min); + + return new Color(r, g, b); + } + + /** + * 图片转Base64 + * + * @param image 图片 + * @return Base64字符串 + */ + private String imageToBase64(BufferedImage image) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(image, "png", baos); + byte[] imageBytes = baos.toByteArray(); + return "data:image/png;base64," + Base64.getEncoder().encodeToString(imageBytes); + } + + /** + * 验证验证码 + * + * @param inputCode 用户输入的验证码 + * @param correctCode 正确的验证码 + * @return 是否验证通过 + */ + public boolean verifyCaptcha(String inputCode, String correctCode) { + if (inputCode == null || correctCode == null) { + return false; + } + return inputCode.equalsIgnoreCase(correctCode); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/utils/FileUtils.java b/backend/src/main/java/com/stdproject/utils/FileUtils.java new file mode 100644 index 0000000..63b2c01 --- /dev/null +++ b/backend/src/main/java/com/stdproject/utils/FileUtils.java @@ -0,0 +1,219 @@ +package com.stdproject.utils; + +import com.stdproject.common.BusinessException; +import com.stdproject.common.ResultCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +/** + * 文件工具类 + * + * @author StdProject + */ +@Component +@Slf4j +public class FileUtils { + + @Value("${file.upload.path:/uploads}") + private String uploadPath; + + @Value("${file.upload.max-size:10485760}") + private long maxFileSize; // 默认10MB + + /** + * 允许的图片文件类型 + */ + private static final List ALLOWED_IMAGE_TYPES = Arrays.asList( + "jpg", "jpeg", "png", "gif", "bmp", "webp" + ); + + /** + * 允许的文档文件类型 + */ + private static final List ALLOWED_DOCUMENT_TYPES = Arrays.asList( + "pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt" + ); + + /** + * 上传文件 + * + * @param file 文件 + * @param subDir 子目录 + * @return 文件相对路径 + */ + public String uploadFile(MultipartFile file, String subDir) { + if (file == null || file.isEmpty()) { + throw new BusinessException("文件不能为空"); + } + + // 检查文件大小 + if (file.getSize() > maxFileSize) { + throw new BusinessException( "文件大小不能超过" + (maxFileSize / 1024 / 1024) + "MB"); + } + + // 获取原始文件名和扩展名 + String originalFilename = file.getOriginalFilename(); + if (originalFilename == null || originalFilename.trim().isEmpty()) { + throw new BusinessException( "文件名不能为空"); + } + + String extension = getFileExtension(originalFilename); + if (extension.isEmpty()) { + throw new BusinessException( "文件必须有扩展名"); + } + + // 检查文件类型 + if (!isAllowedFileType(extension)) { + throw new BusinessException( "不支持的文件类型: " + extension); + } + + try { + // 创建目录结构:uploadPath/subDir/yyyy/MM/dd/ + String dateDir = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")); + String fullSubDir = subDir + "/" + dateDir; + Path uploadDir = Paths.get(uploadPath, fullSubDir); + + if (!Files.exists(uploadDir)) { + Files.createDirectories(uploadDir); + } + + // 生成新文件名 + String newFileName = UUID.randomUUID().toString().replace("-", "") + "." + extension; + Path filePath = uploadDir.resolve(newFileName); + + // 保存文件 + file.transferTo(filePath.toFile()); + + // 返回相对路径 + return fullSubDir + "/" + newFileName; + + } catch (IOException e) { + log.error("文件上传失败: {}", e.getMessage(), e); + throw new BusinessException( "文件上传失败"); + } + } + + /** + * 删除文件 + * + * @param filePath 文件相对路径 + * @return 是否删除成功 + */ + public boolean deleteFile(String filePath) { + if (filePath == null || filePath.trim().isEmpty()) { + return false; + } + + try { + Path fullPath = Paths.get(uploadPath, filePath); + return Files.deleteIfExists(fullPath); + } catch (IOException e) { + log.error("删除文件失败: {}", e.getMessage(), e); + return false; + } + } + + /** + * 获取文件扩展名 + * + * @param filename 文件名 + * @return 扩展名(小写) + */ + public String getFileExtension(String filename) { + if (filename == null || filename.trim().isEmpty()) { + return ""; + } + + int lastDotIndex = filename.lastIndexOf('.'); + if (lastDotIndex == -1 || lastDotIndex == filename.length() - 1) { + return ""; + } + + return filename.substring(lastDotIndex + 1).toLowerCase(); + } + + /** + * 检查是否为允许的文件类型 + * + * @param extension 文件扩展名 + * @return 是否允许 + */ + public boolean isAllowedFileType(String extension) { + if (extension == null || extension.trim().isEmpty()) { + return false; + } + + String lowerExtension = extension.toLowerCase(); + return ALLOWED_IMAGE_TYPES.contains(lowerExtension) || + ALLOWED_DOCUMENT_TYPES.contains(lowerExtension); + } + + /** + * 检查是否为图片文件 + * + * @param extension 文件扩展名 + * @return 是否为图片 + */ + public boolean isImageFile(String extension) { + if (extension == null || extension.trim().isEmpty()) { + return false; + } + return ALLOWED_IMAGE_TYPES.contains(extension.toLowerCase()); + } + + /** + * 获取文件完整路径 + * + * @param relativePath 相对路径 + * @return 完整路径 + */ + public String getFullPath(String relativePath) { + if (relativePath == null || relativePath.trim().isEmpty()) { + return ""; + } + return Paths.get(uploadPath, relativePath).toString(); + } + + /** + * 检查文件是否存在 + * + * @param relativePath 相对路径 + * @return 是否存在 + */ + public boolean fileExists(String relativePath) { + if (relativePath == null || relativePath.trim().isEmpty()) { + return false; + } + return Files.exists(Paths.get(uploadPath, relativePath)); + } + + /** + * 格式化文件大小 + * + * @param size 文件大小(字节) + * @return 格式化后的大小 + */ + public static String formatFileSize(long size) { + if (size < 1024) { + return size + " B"; + } else if (size < 1024 * 1024) { + return String.format("%.1f KB", size / 1024.0); + } else if (size < 1024 * 1024 * 1024) { + return String.format("%.1f MB", size / (1024.0 * 1024.0)); + } else { + return String.format("%.1f GB", size / (1024.0 * 1024.0 * 1024.0)); + } + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/utils/JwtUtils.java b/backend/src/main/java/com/stdproject/utils/JwtUtils.java new file mode 100644 index 0000000..f1a0238 --- /dev/null +++ b/backend/src/main/java/com/stdproject/utils/JwtUtils.java @@ -0,0 +1,168 @@ +package com.stdproject.utils; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.JwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.crypto.SecretKey; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * JWT工具类 + * 用于生成、解析和验证JWT令牌 + * + * @author StdProject + */ +@Component +public class JwtUtils { + + @Value("${spring.security.jwt.secret}") + private String secret; + + @Value("${spring.security.jwt.expiration-ms}") + private Long expirationMs; + + /** + * 生成JWT令牌 + * + * @param username 用户名 + * @param userId 用户ID + * @return JWT令牌 + */ + public String generateToken(String username, String userId) { + Map claims = new HashMap<>(); + claims.put("userId", userId); + claims.put("username", username); + return createToken(claims, username); + } + + /** + * 创建JWT令牌 + * + * @param claims 声明 + * @param subject 主题 + * @return JWT令牌 + */ + private String createToken(Map claims, String subject) { + Date now = new Date(); + Date expiryDate = new Date(now.getTime() + expirationMs); + + return Jwts.builder() + .setClaims(claims) + .setSubject(subject) + .setIssuedAt(now) + .setExpiration(expiryDate) + .signWith(getSigningKey(), SignatureAlgorithm.HS512) + .compact(); + } + + /** + * 从JWT令牌中获取用户名 + * + * @param token JWT令牌 + * @return 用户名 + */ + public String getUsernameFromToken(String token) { + return getClaimFromToken(token, Claims::getSubject); + } + + /** + * 从JWT令牌中获取用户ID + * + * @param token JWT令牌 + * @return 用户ID + */ + public String getUserIdFromToken(String token) { + return getClaimFromToken(token, claims -> claims.get("userId", String.class)); + } + + /** + * 从JWT令牌中获取过期时间 + * + * @param token JWT令牌 + * @return 过期时间 + */ + public Date getExpirationDateFromToken(String token) { + return getClaimFromToken(token, Claims::getExpiration); + } + + /** + * 从JWT令牌中获取声明 + * + * @param token JWT令牌 + * @param claimsResolver 声明解析器 + * @param 返回类型 + * @return 声明值 + */ + public T getClaimFromToken(String token, ClaimsResolver claimsResolver) { + final Claims claims = getAllClaimsFromToken(token); + return claimsResolver.resolve(claims); + } + + /** + * 从JWT令牌中获取所有声明 + * + * @param token JWT令牌 + * @return 所有声明 + */ + private Claims getAllClaimsFromToken(String token) { + return Jwts.parserBuilder() + .setSigningKey(getSigningKey()) + .build() + .parseClaimsJws(token) + .getBody(); + } + + /** + * 检查JWT令牌是否过期 + * + * @param token JWT令牌 + * @return 是否过期 + */ + public Boolean isTokenExpired(String token) { + final Date expiration = getExpirationDateFromToken(token); + return expiration.before(new Date()); + } + + /** + * 验证JWT令牌 + * + * @param token JWT令牌 + * @param username 用户名 + * @return 是否有效 + */ + public Boolean validateToken(String token, String username) { + try { + final String tokenUsername = getUsernameFromToken(token); + return (username.equals(tokenUsername) && !isTokenExpired(token)); + } catch (JwtException | IllegalArgumentException e) { + return false; + } + } + + /** + * 获取签名密钥 + * + * @return 签名密钥 + */ + private SecretKey getSigningKey() { + byte[] keyBytes = secret.getBytes(); + return Keys.hmacShaKeyFor(keyBytes); + } + + /** + * 声明解析器接口 + * + * @param 返回类型 + */ + @FunctionalInterface + public interface ClaimsResolver { + T resolve(Claims claims); + } +} \ No newline at end of file diff --git a/backend/src/main/java/com/stdproject/utils/PasswordUtils.java b/backend/src/main/java/com/stdproject/utils/PasswordUtils.java new file mode 100644 index 0000000..401ef9a --- /dev/null +++ b/backend/src/main/java/com/stdproject/utils/PasswordUtils.java @@ -0,0 +1,85 @@ +package com.stdproject.utils; + +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +/** + * 密码工具类 + * 用于密码的加密和验证 + * + * @author StdProject + */ +@Component +public class PasswordUtils { + + private static final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + + /** + * 加密密码 + * + * @param rawPassword 原始密码 + * @return 加密后的密码 + */ + public static String encodePassword(String rawPassword) { + return passwordEncoder.encode(rawPassword); + } + + /** + * 验证密码 + * + * @param rawPassword 原始密码 + * @param encodedPassword 加密后的密码 + * @return 是否匹配 + */ + public static boolean matches(String rawPassword, String encodedPassword) { + return passwordEncoder.matches(rawPassword, encodedPassword); + } + + /** + * 生成随机密码 + * + * @param length 密码长度 + * @return 随机密码 + */ + public static String generateRandomPassword(int length) { + String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + StringBuilder password = new StringBuilder(); + for (int i = 0; i < length; i++) { + int index = (int) (Math.random() * chars.length()); + password.append(chars.charAt(index)); + } + return password.toString(); + } + + /** + * 验证密码强度 + * + * @param password 密码 + * @return 是否符合强度要求 + */ + public static boolean isStrongPassword(String password) { + if (password == null || password.length() < 8) { + return false; + } + + boolean hasUpper = false; + boolean hasLower = false; + boolean hasDigit = false; + boolean hasSpecial = false; + + for (char c : password.toCharArray()) { + if (Character.isUpperCase(c)) { + hasUpper = true; + } else if (Character.isLowerCase(c)) { + hasLower = true; + } else if (Character.isDigit(c)) { + hasDigit = true; + } else if (!Character.isLetterOrDigit(c)) { + hasSpecial = true; + } + } + + return hasUpper && hasLower && hasDigit && hasSpecial; + } +} \ No newline at end of file diff --git a/backend/src/main/resources/.env b/backend/src/main/resources/.env new file mode 100644 index 0000000..4fe5114 --- /dev/null +++ b/backend/src/main/resources/.env @@ -0,0 +1,14 @@ +# 数据库配置 +DB_URL=jdbc:mysql://your-host:3306/your-db +DB_USERNAME=your-username +DB_PASSWORD=your-password + +# JWT配置 +JWT_SECRET=your-super-secret-key +JWT_EXPIRATION=86400000 + +# 环境配置 +SPRING_PROFILES_ACTIVE=dev + +# CORS配置 +CORS_ALLOWED_ORIGINS=https://your-frontend.com \ No newline at end of file diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml new file mode 100644 index 0000000..730a5d0 --- /dev/null +++ b/backend/src/main/resources/application.yml @@ -0,0 +1,193 @@ +server: + port: 8080 + servlet: + context-path: / + encoding: + charset: UTF-8 + enabled: true + force: true + compression: + enabled: true + mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json + min-response-size: 1024 + +spring: + profiles: + active: ${SPRING_PROFILES_ACTIVE:dev} + application: + name: stdproject-backend + datasource: + url: ${DB_URL:jdbc:mysql://121.37.111.42:3306/gisbi-demodb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true} + username: ${DB_USERNAME:root} + password: ${DB_PASSWORD:mysql_F8ysiK@2024} + driver-class-name: com.mysql.cj.jdbc.Driver + # HikariCP连接池配置 + hikari: + pool-name: StdProjectHikariCP + minimum-idle: 5 + maximum-pool-size: 20 + auto-commit: true + idle-timeout: 30000 + max-lifetime: 1800000 + connection-timeout: 30000 + connection-test-query: SELECT 1 +# url: jdbc:sqlite:D:/Trae_space/StdProject/backend/db/project.db +# username: # SQLite 不需要用户名 +# password: # SQLite 不需要密码 +# driver-class-name: org.sqlite.JDBC +# hikari: +# pool-name: StdProjectHikariCP +# minimum-idle: 5 +# maximum-pool-size: 20 +# auto-commit: true +# idle-timeout: 30000 +# max-lifetime: 1800000 +# connection-timeout: 30000 +# connection-test-query: SELECT 1 + + cache: + jcache: + config: classpath:ehcache.xml # 指定Ehcache配置文件路径 + security: + cors: + allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:3000,http://localhost:8080} + max-age: ${CORS_MAX_AGE:3600} # 预检请求的缓存时间(秒) + jwt: + enabled: ${JWT_ENABLED:true} # 控制是否启用JWT认证 + secret: ${JWT_SECRET:YourJWTSecretKeyForStdProjectBackendApplicationWhichIsVeryLongAndSecure2024!@#$%^&*()} + expiration-ms: ${JWT_EXPIRATION:86400000} # Token 过期时间 (例如: 24小时) + refresh-expiration-ms: ${JWT_REFRESH_EXPIRATION:604800000} # 刷新Token过期时间 (例如: 7天) + +mybatis-plus: + mapper-locations: classpath*:/mapper/**/*.xml # MyBatis Mapper XML文件位置 + type-aliases-package: com.stdproject.entity + global-config: + db-config: + id-type: ASSIGN_ID # ID生成策略,assign_id 表示手动分配ID,通常使用雪花算法等 + table-prefix: ${DB_TABLE_PREFIX:} # 如果表名有统一前缀,可以在这里配置 + logic-delete-field: deleted # 逻辑删除字段名 + logic-delete-value: 1 # 逻辑删除值 + logic-not-delete-value: 0 # 逻辑未删除值 + banner: false # 关闭MyBatis-Plus启动横幅 + configuration: + map-underscore-to-camel-case: true # 开启驼峰命名转换 + cache-enabled: true # 开启二级缓存 + lazy-loading-enabled: true # 开启延迟加载 + multiple-result-sets-enabled: true # 开启多结果集 + use-column-label: true # 使用列标签 + use-generated-keys: true # 使用生成的主键 + auto-mapping-behavior: partial # 自动映射行为 + default-executor-type: simple # 默认执行器类型 + default-statement-timeout: 25000 # 默认语句超时时间 + log-impl: ${MYBATIS_LOG_IMPL:org.apache.ibatis.logging.nologging.NoLoggingImpl} # SQL日志实现 + +logging: + config: classpath:logback-spring.xml # Logback配置文件 + level: + root: ${LOG_LEVEL_ROOT:INFO} + com.stdproject: ${LOG_LEVEL_APP:DEBUG} + org.springframework.security: ${LOG_LEVEL_SECURITY:WARN} + org.hibernate.SQL: ${LOG_LEVEL_SQL:WARN} + org.hibernate.type.descriptor.sql.BasicBinder: ${LOG_LEVEL_SQL_PARAMS:WARN} + pattern: + console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" + file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" + +springdoc: + api-docs: + path: /v3/api-docs + enabled: ${SWAGGER_ENABLED:true} + swagger-ui: + path: /swagger-ui.html + enabled: ${SWAGGER_UI_ENABLED:true} + operations-sorter: alpha + tags-sorter: alpha + try-it-out-enabled: true + filter: true + default-consumes-media-type: application/json + default-produces-media-type: application/json + show-actuator: ${SWAGGER_SHOW_ACTUATOR:true} + packages-to-scan: com.stdproject.controller + +# 管理端点配置 +management: + endpoints: + web: + exposure: + include: ${ACTUATOR_ENDPOINTS:health,info,metrics} + base-path: /actuator + endpoint: + health: + show-details: ${ACTUATOR_HEALTH_DETAILS:when-authorized} + info: + enabled: true + info: + env: + enabled: true + java: + enabled: true + os: + enabled: true + +# 应用信息配置 +info: + app: + name: ${spring.application.name} + description: StdProject Backend Application + version: 1.0.0 + encoding: UTF-8 + java: + version: ${java.version} + +--- +# 开发环境配置 +spring: + config: + activate: + on-profile: dev + jpa: + show-sql: true + security: + jwt: + enabled: false +logging: + level: + com.stdproject: DEBUG + org.hibernate.SQL: DEBUG + org.hibernate.type.descriptor.sql.BasicBinder: TRACE +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl +springdoc: + swagger-ui: + enabled: true + +--- +# 生产环境配置 +spring: + config: + activate: + on-profile: prod + jpa: + show-sql: false + security: + jwt: + enabled: true +logging: + level: + root: WARN + com.stdproject: INFO + org.springframework.security: ERROR +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl +springdoc: + api-docs: + enabled: false + swagger-ui: + enabled: false +management: + endpoints: + web: + exposure: + include: health,info \ No newline at end of file diff --git a/backend/src/main/resources/ehcache.xml b/backend/src/main/resources/ehcache.xml new file mode 100644 index 0000000..0c9ff84 --- /dev/null +++ b/backend/src/main/resources/ehcache.xml @@ -0,0 +1,58 @@ + + + + + + 3600 + + + 1000 + 10 + + + + + + + 30 + + + + + + + 60 + + + + + + + 60 + + + + + + + 60 + + + + + + + 2 + + + + + + + 1 + + + + \ No newline at end of file diff --git a/backend/src/main/resources/logback-spring.xml b/backend/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..43814d0 --- /dev/null +++ b/backend/src/main/resources/logback-spring.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + + + + ${LOG_PATH}/info.log + + ${LOG_PATH}/info.%d{yyyy-MM-dd}.log + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + INFO + ACCEPT + DENY + + + + + ${LOG_PATH}/error.log + + ${LOG_PATH}/error.%d{yyyy-MM-dd}.log + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/target/classes/.env b/backend/target/classes/.env new file mode 100644 index 0000000..4fe5114 --- /dev/null +++ b/backend/target/classes/.env @@ -0,0 +1,14 @@ +# 数据库配置 +DB_URL=jdbc:mysql://your-host:3306/your-db +DB_USERNAME=your-username +DB_PASSWORD=your-password + +# JWT配置 +JWT_SECRET=your-super-secret-key +JWT_EXPIRATION=86400000 + +# 环境配置 +SPRING_PROFILES_ACTIVE=dev + +# CORS配置 +CORS_ALLOWED_ORIGINS=https://your-frontend.com \ No newline at end of file diff --git a/backend/target/classes/application.yml b/backend/target/classes/application.yml new file mode 100644 index 0000000..730a5d0 --- /dev/null +++ b/backend/target/classes/application.yml @@ -0,0 +1,193 @@ +server: + port: 8080 + servlet: + context-path: / + encoding: + charset: UTF-8 + enabled: true + force: true + compression: + enabled: true + mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json + min-response-size: 1024 + +spring: + profiles: + active: ${SPRING_PROFILES_ACTIVE:dev} + application: + name: stdproject-backend + datasource: + url: ${DB_URL:jdbc:mysql://121.37.111.42:3306/gisbi-demodb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true} + username: ${DB_USERNAME:root} + password: ${DB_PASSWORD:mysql_F8ysiK@2024} + driver-class-name: com.mysql.cj.jdbc.Driver + # HikariCP连接池配置 + hikari: + pool-name: StdProjectHikariCP + minimum-idle: 5 + maximum-pool-size: 20 + auto-commit: true + idle-timeout: 30000 + max-lifetime: 1800000 + connection-timeout: 30000 + connection-test-query: SELECT 1 +# url: jdbc:sqlite:D:/Trae_space/StdProject/backend/db/project.db +# username: # SQLite 不需要用户名 +# password: # SQLite 不需要密码 +# driver-class-name: org.sqlite.JDBC +# hikari: +# pool-name: StdProjectHikariCP +# minimum-idle: 5 +# maximum-pool-size: 20 +# auto-commit: true +# idle-timeout: 30000 +# max-lifetime: 1800000 +# connection-timeout: 30000 +# connection-test-query: SELECT 1 + + cache: + jcache: + config: classpath:ehcache.xml # 指定Ehcache配置文件路径 + security: + cors: + allowed-origins: ${CORS_ALLOWED_ORIGINS:http://localhost:3000,http://localhost:8080} + max-age: ${CORS_MAX_AGE:3600} # 预检请求的缓存时间(秒) + jwt: + enabled: ${JWT_ENABLED:true} # 控制是否启用JWT认证 + secret: ${JWT_SECRET:YourJWTSecretKeyForStdProjectBackendApplicationWhichIsVeryLongAndSecure2024!@#$%^&*()} + expiration-ms: ${JWT_EXPIRATION:86400000} # Token 过期时间 (例如: 24小时) + refresh-expiration-ms: ${JWT_REFRESH_EXPIRATION:604800000} # 刷新Token过期时间 (例如: 7天) + +mybatis-plus: + mapper-locations: classpath*:/mapper/**/*.xml # MyBatis Mapper XML文件位置 + type-aliases-package: com.stdproject.entity + global-config: + db-config: + id-type: ASSIGN_ID # ID生成策略,assign_id 表示手动分配ID,通常使用雪花算法等 + table-prefix: ${DB_TABLE_PREFIX:} # 如果表名有统一前缀,可以在这里配置 + logic-delete-field: deleted # 逻辑删除字段名 + logic-delete-value: 1 # 逻辑删除值 + logic-not-delete-value: 0 # 逻辑未删除值 + banner: false # 关闭MyBatis-Plus启动横幅 + configuration: + map-underscore-to-camel-case: true # 开启驼峰命名转换 + cache-enabled: true # 开启二级缓存 + lazy-loading-enabled: true # 开启延迟加载 + multiple-result-sets-enabled: true # 开启多结果集 + use-column-label: true # 使用列标签 + use-generated-keys: true # 使用生成的主键 + auto-mapping-behavior: partial # 自动映射行为 + default-executor-type: simple # 默认执行器类型 + default-statement-timeout: 25000 # 默认语句超时时间 + log-impl: ${MYBATIS_LOG_IMPL:org.apache.ibatis.logging.nologging.NoLoggingImpl} # SQL日志实现 + +logging: + config: classpath:logback-spring.xml # Logback配置文件 + level: + root: ${LOG_LEVEL_ROOT:INFO} + com.stdproject: ${LOG_LEVEL_APP:DEBUG} + org.springframework.security: ${LOG_LEVEL_SECURITY:WARN} + org.hibernate.SQL: ${LOG_LEVEL_SQL:WARN} + org.hibernate.type.descriptor.sql.BasicBinder: ${LOG_LEVEL_SQL_PARAMS:WARN} + pattern: + console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" + file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n" + +springdoc: + api-docs: + path: /v3/api-docs + enabled: ${SWAGGER_ENABLED:true} + swagger-ui: + path: /swagger-ui.html + enabled: ${SWAGGER_UI_ENABLED:true} + operations-sorter: alpha + tags-sorter: alpha + try-it-out-enabled: true + filter: true + default-consumes-media-type: application/json + default-produces-media-type: application/json + show-actuator: ${SWAGGER_SHOW_ACTUATOR:true} + packages-to-scan: com.stdproject.controller + +# 管理端点配置 +management: + endpoints: + web: + exposure: + include: ${ACTUATOR_ENDPOINTS:health,info,metrics} + base-path: /actuator + endpoint: + health: + show-details: ${ACTUATOR_HEALTH_DETAILS:when-authorized} + info: + enabled: true + info: + env: + enabled: true + java: + enabled: true + os: + enabled: true + +# 应用信息配置 +info: + app: + name: ${spring.application.name} + description: StdProject Backend Application + version: 1.0.0 + encoding: UTF-8 + java: + version: ${java.version} + +--- +# 开发环境配置 +spring: + config: + activate: + on-profile: dev + jpa: + show-sql: true + security: + jwt: + enabled: false +logging: + level: + com.stdproject: DEBUG + org.hibernate.SQL: DEBUG + org.hibernate.type.descriptor.sql.BasicBinder: TRACE +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl +springdoc: + swagger-ui: + enabled: true + +--- +# 生产环境配置 +spring: + config: + activate: + on-profile: prod + jpa: + show-sql: false + security: + jwt: + enabled: true +logging: + level: + root: WARN + com.stdproject: INFO + org.springframework.security: ERROR +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl +springdoc: + api-docs: + enabled: false + swagger-ui: + enabled: false +management: + endpoints: + web: + exposure: + include: health,info \ No newline at end of file diff --git a/backend/target/classes/com/stdproject/ProjectApplication.class b/backend/target/classes/com/stdproject/ProjectApplication.class new file mode 100644 index 0000000..97e1562 Binary files /dev/null and b/backend/target/classes/com/stdproject/ProjectApplication.class differ diff --git a/backend/target/classes/com/stdproject/common/BusinessException.class b/backend/target/classes/com/stdproject/common/BusinessException.class new file mode 100644 index 0000000..6ac0804 Binary files /dev/null and b/backend/target/classes/com/stdproject/common/BusinessException.class differ diff --git a/backend/target/classes/com/stdproject/common/Constants.class b/backend/target/classes/com/stdproject/common/Constants.class new file mode 100644 index 0000000..a907378 Binary files /dev/null and b/backend/target/classes/com/stdproject/common/Constants.class differ diff --git a/backend/target/classes/com/stdproject/common/DataPermission.class b/backend/target/classes/com/stdproject/common/DataPermission.class new file mode 100644 index 0000000..7f81368 Binary files /dev/null and b/backend/target/classes/com/stdproject/common/DataPermission.class differ diff --git a/backend/target/classes/com/stdproject/common/GlobalExceptionHandler.class b/backend/target/classes/com/stdproject/common/GlobalExceptionHandler.class new file mode 100644 index 0000000..5130455 Binary files /dev/null and b/backend/target/classes/com/stdproject/common/GlobalExceptionHandler.class differ diff --git a/backend/target/classes/com/stdproject/common/OperationLog.class b/backend/target/classes/com/stdproject/common/OperationLog.class new file mode 100644 index 0000000..70ab2fd Binary files /dev/null and b/backend/target/classes/com/stdproject/common/OperationLog.class differ diff --git a/backend/target/classes/com/stdproject/common/OperationLogAspect.class b/backend/target/classes/com/stdproject/common/OperationLogAspect.class new file mode 100644 index 0000000..74f7322 Binary files /dev/null and b/backend/target/classes/com/stdproject/common/OperationLogAspect.class differ diff --git a/backend/target/classes/com/stdproject/common/PageRequest.class b/backend/target/classes/com/stdproject/common/PageRequest.class new file mode 100644 index 0000000..5e88b3c Binary files /dev/null and b/backend/target/classes/com/stdproject/common/PageRequest.class differ diff --git a/backend/target/classes/com/stdproject/common/Result.class b/backend/target/classes/com/stdproject/common/Result.class new file mode 100644 index 0000000..354524e Binary files /dev/null and b/backend/target/classes/com/stdproject/common/Result.class differ diff --git a/backend/target/classes/com/stdproject/common/ResultCode.class b/backend/target/classes/com/stdproject/common/ResultCode.class new file mode 100644 index 0000000..8c06040 Binary files /dev/null and b/backend/target/classes/com/stdproject/common/ResultCode.class differ diff --git a/backend/target/classes/com/stdproject/config/CacheConfig.class b/backend/target/classes/com/stdproject/config/CacheConfig.class new file mode 100644 index 0000000..6f005dd Binary files /dev/null and b/backend/target/classes/com/stdproject/config/CacheConfig.class differ diff --git a/backend/target/classes/com/stdproject/config/CustomUserDetailsService.class b/backend/target/classes/com/stdproject/config/CustomUserDetailsService.class new file mode 100644 index 0000000..381fcc4 Binary files /dev/null and b/backend/target/classes/com/stdproject/config/CustomUserDetailsService.class differ diff --git a/backend/target/classes/com/stdproject/config/JwtAuthenticationEntryPoint.class b/backend/target/classes/com/stdproject/config/JwtAuthenticationEntryPoint.class new file mode 100644 index 0000000..6e858a9 Binary files /dev/null and b/backend/target/classes/com/stdproject/config/JwtAuthenticationEntryPoint.class differ diff --git a/backend/target/classes/com/stdproject/config/JwtAuthenticationFilter.class b/backend/target/classes/com/stdproject/config/JwtAuthenticationFilter.class new file mode 100644 index 0000000..27f22c4 Binary files /dev/null and b/backend/target/classes/com/stdproject/config/JwtAuthenticationFilter.class differ diff --git a/backend/target/classes/com/stdproject/config/MybatisPlusConfig.class b/backend/target/classes/com/stdproject/config/MybatisPlusConfig.class new file mode 100644 index 0000000..bca6ecf Binary files /dev/null and b/backend/target/classes/com/stdproject/config/MybatisPlusConfig.class differ diff --git a/backend/target/classes/com/stdproject/config/PasswordEncoderConfig.class b/backend/target/classes/com/stdproject/config/PasswordEncoderConfig.class new file mode 100644 index 0000000..b04c9e6 Binary files /dev/null and b/backend/target/classes/com/stdproject/config/PasswordEncoderConfig.class differ diff --git a/backend/target/classes/com/stdproject/config/SecurityConfig.class b/backend/target/classes/com/stdproject/config/SecurityConfig.class new file mode 100644 index 0000000..5721b53 Binary files /dev/null and b/backend/target/classes/com/stdproject/config/SecurityConfig.class differ diff --git a/backend/target/classes/com/stdproject/config/SwaggerConfig.class b/backend/target/classes/com/stdproject/config/SwaggerConfig.class new file mode 100644 index 0000000..681d483 Binary files /dev/null and b/backend/target/classes/com/stdproject/config/SwaggerConfig.class differ diff --git a/backend/target/classes/com/stdproject/config/WebConfig.class b/backend/target/classes/com/stdproject/config/WebConfig.class new file mode 100644 index 0000000..10efb1e Binary files /dev/null and b/backend/target/classes/com/stdproject/config/WebConfig.class differ diff --git a/backend/target/classes/com/stdproject/controller/AppDictionaryController$DictOrderRequest.class b/backend/target/classes/com/stdproject/controller/AppDictionaryController$DictOrderRequest.class new file mode 100644 index 0000000..e349ba5 Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AppDictionaryController$DictOrderRequest.class differ diff --git a/backend/target/classes/com/stdproject/controller/AppDictionaryController.class b/backend/target/classes/com/stdproject/controller/AppDictionaryController.class new file mode 100644 index 0000000..26fa337 Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AppDictionaryController.class differ diff --git a/backend/target/classes/com/stdproject/controller/AppMenuController$MenuOrderRequest.class b/backend/target/classes/com/stdproject/controller/AppMenuController$MenuOrderRequest.class new file mode 100644 index 0000000..c6e8835 Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AppMenuController$MenuOrderRequest.class differ diff --git a/backend/target/classes/com/stdproject/controller/AppMenuController$MenuTreeNode.class b/backend/target/classes/com/stdproject/controller/AppMenuController$MenuTreeNode.class new file mode 100644 index 0000000..6290ba6 Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AppMenuController$MenuTreeNode.class differ diff --git a/backend/target/classes/com/stdproject/controller/AppMenuController.class b/backend/target/classes/com/stdproject/controller/AppMenuController.class new file mode 100644 index 0000000..ebe78d9 Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AppMenuController.class differ diff --git a/backend/target/classes/com/stdproject/controller/AppOptLogController$LogStatistics.class b/backend/target/classes/com/stdproject/controller/AppOptLogController$LogStatistics.class new file mode 100644 index 0000000..d7148b7 Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AppOptLogController$LogStatistics.class differ diff --git a/backend/target/classes/com/stdproject/controller/AppOptLogController.class b/backend/target/classes/com/stdproject/controller/AppOptLogController.class new file mode 100644 index 0000000..7bc3f8d Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AppOptLogController.class differ diff --git a/backend/target/classes/com/stdproject/controller/AppOrganizationController.class b/backend/target/classes/com/stdproject/controller/AppOrganizationController.class new file mode 100644 index 0000000..52a7a2c Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AppOrganizationController.class differ diff --git a/backend/target/classes/com/stdproject/controller/AppRoleController.class b/backend/target/classes/com/stdproject/controller/AppRoleController.class new file mode 100644 index 0000000..183fd66 Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AppRoleController.class differ diff --git a/backend/target/classes/com/stdproject/controller/AppUserController$PasswordResetRequest.class b/backend/target/classes/com/stdproject/controller/AppUserController$PasswordResetRequest.class new file mode 100644 index 0000000..82dde5d Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AppUserController$PasswordResetRequest.class differ diff --git a/backend/target/classes/com/stdproject/controller/AppUserController$PasswordUpdateRequest.class b/backend/target/classes/com/stdproject/controller/AppUserController$PasswordUpdateRequest.class new file mode 100644 index 0000000..c19ce31 Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AppUserController$PasswordUpdateRequest.class differ diff --git a/backend/target/classes/com/stdproject/controller/AppUserController.class b/backend/target/classes/com/stdproject/controller/AppUserController.class new file mode 100644 index 0000000..fb63136 Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AppUserController.class differ diff --git a/backend/target/classes/com/stdproject/controller/AuthController$ChangePasswordRequest.class b/backend/target/classes/com/stdproject/controller/AuthController$ChangePasswordRequest.class new file mode 100644 index 0000000..ea235e0 Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AuthController$ChangePasswordRequest.class differ diff --git a/backend/target/classes/com/stdproject/controller/AuthController$LoginRequest.class b/backend/target/classes/com/stdproject/controller/AuthController$LoginRequest.class new file mode 100644 index 0000000..eff6d92 Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AuthController$LoginRequest.class differ diff --git a/backend/target/classes/com/stdproject/controller/AuthController.class b/backend/target/classes/com/stdproject/controller/AuthController.class new file mode 100644 index 0000000..7caaec5 Binary files /dev/null and b/backend/target/classes/com/stdproject/controller/AuthController.class differ diff --git a/backend/target/classes/com/stdproject/entity/AppDictionary.class b/backend/target/classes/com/stdproject/entity/AppDictionary.class new file mode 100644 index 0000000..6fff69e Binary files /dev/null and b/backend/target/classes/com/stdproject/entity/AppDictionary.class differ diff --git a/backend/target/classes/com/stdproject/entity/AppMenu.class b/backend/target/classes/com/stdproject/entity/AppMenu.class new file mode 100644 index 0000000..327d7c9 Binary files /dev/null and b/backend/target/classes/com/stdproject/entity/AppMenu.class differ diff --git a/backend/target/classes/com/stdproject/entity/AppOptLog.class b/backend/target/classes/com/stdproject/entity/AppOptLog.class new file mode 100644 index 0000000..9b3cf95 Binary files /dev/null and b/backend/target/classes/com/stdproject/entity/AppOptLog.class differ diff --git a/backend/target/classes/com/stdproject/entity/AppOrganization.class b/backend/target/classes/com/stdproject/entity/AppOrganization.class new file mode 100644 index 0000000..940ebb8 Binary files /dev/null and b/backend/target/classes/com/stdproject/entity/AppOrganization.class differ diff --git a/backend/target/classes/com/stdproject/entity/AppRole.class b/backend/target/classes/com/stdproject/entity/AppRole.class new file mode 100644 index 0000000..a7edac7 Binary files /dev/null and b/backend/target/classes/com/stdproject/entity/AppRole.class differ diff --git a/backend/target/classes/com/stdproject/entity/AppRoleMenu.class b/backend/target/classes/com/stdproject/entity/AppRoleMenu.class new file mode 100644 index 0000000..f60e452 Binary files /dev/null and b/backend/target/classes/com/stdproject/entity/AppRoleMenu.class differ diff --git a/backend/target/classes/com/stdproject/entity/AppRoleUser.class b/backend/target/classes/com/stdproject/entity/AppRoleUser.class new file mode 100644 index 0000000..7ecfad0 Binary files /dev/null and b/backend/target/classes/com/stdproject/entity/AppRoleUser.class differ diff --git a/backend/target/classes/com/stdproject/entity/AppUser.class b/backend/target/classes/com/stdproject/entity/AppUser.class new file mode 100644 index 0000000..673040e Binary files /dev/null and b/backend/target/classes/com/stdproject/entity/AppUser.class differ diff --git a/backend/target/classes/com/stdproject/mapper/AppDictionaryMapper.class b/backend/target/classes/com/stdproject/mapper/AppDictionaryMapper.class new file mode 100644 index 0000000..142654c Binary files /dev/null and b/backend/target/classes/com/stdproject/mapper/AppDictionaryMapper.class differ diff --git a/backend/target/classes/com/stdproject/mapper/AppMenuMapper.class b/backend/target/classes/com/stdproject/mapper/AppMenuMapper.class new file mode 100644 index 0000000..0c41b32 Binary files /dev/null and b/backend/target/classes/com/stdproject/mapper/AppMenuMapper.class differ diff --git a/backend/target/classes/com/stdproject/mapper/AppOptLogMapper.class b/backend/target/classes/com/stdproject/mapper/AppOptLogMapper.class new file mode 100644 index 0000000..45dea8d Binary files /dev/null and b/backend/target/classes/com/stdproject/mapper/AppOptLogMapper.class differ diff --git a/backend/target/classes/com/stdproject/mapper/AppOrganizationMapper.class b/backend/target/classes/com/stdproject/mapper/AppOrganizationMapper.class new file mode 100644 index 0000000..c07b032 Binary files /dev/null and b/backend/target/classes/com/stdproject/mapper/AppOrganizationMapper.class differ diff --git a/backend/target/classes/com/stdproject/mapper/AppRoleMapper.class b/backend/target/classes/com/stdproject/mapper/AppRoleMapper.class new file mode 100644 index 0000000..058ad12 Binary files /dev/null and b/backend/target/classes/com/stdproject/mapper/AppRoleMapper.class differ diff --git a/backend/target/classes/com/stdproject/mapper/AppRoleMenuMapper.class b/backend/target/classes/com/stdproject/mapper/AppRoleMenuMapper.class new file mode 100644 index 0000000..7cdeed5 Binary files /dev/null and b/backend/target/classes/com/stdproject/mapper/AppRoleMenuMapper.class differ diff --git a/backend/target/classes/com/stdproject/mapper/AppRoleUserMapper.class b/backend/target/classes/com/stdproject/mapper/AppRoleUserMapper.class new file mode 100644 index 0000000..53c671d Binary files /dev/null and b/backend/target/classes/com/stdproject/mapper/AppRoleUserMapper.class differ diff --git a/backend/target/classes/com/stdproject/mapper/AppUserMapper.class b/backend/target/classes/com/stdproject/mapper/AppUserMapper.class new file mode 100644 index 0000000..d27b650 Binary files /dev/null and b/backend/target/classes/com/stdproject/mapper/AppUserMapper.class differ diff --git a/backend/target/classes/com/stdproject/service/IAppDictionaryService.class b/backend/target/classes/com/stdproject/service/IAppDictionaryService.class new file mode 100644 index 0000000..77a2cac Binary files /dev/null and b/backend/target/classes/com/stdproject/service/IAppDictionaryService.class differ diff --git a/backend/target/classes/com/stdproject/service/IAppMenuService.class b/backend/target/classes/com/stdproject/service/IAppMenuService.class new file mode 100644 index 0000000..4963072 Binary files /dev/null and b/backend/target/classes/com/stdproject/service/IAppMenuService.class differ diff --git a/backend/target/classes/com/stdproject/service/IAppOptLogService.class b/backend/target/classes/com/stdproject/service/IAppOptLogService.class new file mode 100644 index 0000000..a426f83 Binary files /dev/null and b/backend/target/classes/com/stdproject/service/IAppOptLogService.class differ diff --git a/backend/target/classes/com/stdproject/service/IAppOrganizationService.class b/backend/target/classes/com/stdproject/service/IAppOrganizationService.class new file mode 100644 index 0000000..1cf19c5 Binary files /dev/null and b/backend/target/classes/com/stdproject/service/IAppOrganizationService.class differ diff --git a/backend/target/classes/com/stdproject/service/IAppRoleMenuService.class b/backend/target/classes/com/stdproject/service/IAppRoleMenuService.class new file mode 100644 index 0000000..0fa6eb1 Binary files /dev/null and b/backend/target/classes/com/stdproject/service/IAppRoleMenuService.class differ diff --git a/backend/target/classes/com/stdproject/service/IAppRoleService.class b/backend/target/classes/com/stdproject/service/IAppRoleService.class new file mode 100644 index 0000000..730082e Binary files /dev/null and b/backend/target/classes/com/stdproject/service/IAppRoleService.class differ diff --git a/backend/target/classes/com/stdproject/service/IAppRoleUserService.class b/backend/target/classes/com/stdproject/service/IAppRoleUserService.class new file mode 100644 index 0000000..69de13d Binary files /dev/null and b/backend/target/classes/com/stdproject/service/IAppRoleUserService.class differ diff --git a/backend/target/classes/com/stdproject/service/IAppUserService.class b/backend/target/classes/com/stdproject/service/IAppUserService.class new file mode 100644 index 0000000..dcfec66 Binary files /dev/null and b/backend/target/classes/com/stdproject/service/IAppUserService.class differ diff --git a/backend/target/classes/com/stdproject/service/impl/AppDictionaryServiceImpl.class b/backend/target/classes/com/stdproject/service/impl/AppDictionaryServiceImpl.class new file mode 100644 index 0000000..b5fec50 Binary files /dev/null and b/backend/target/classes/com/stdproject/service/impl/AppDictionaryServiceImpl.class differ diff --git a/backend/target/classes/com/stdproject/service/impl/AppMenuServiceImpl.class b/backend/target/classes/com/stdproject/service/impl/AppMenuServiceImpl.class new file mode 100644 index 0000000..c44b068 Binary files /dev/null and b/backend/target/classes/com/stdproject/service/impl/AppMenuServiceImpl.class differ diff --git a/backend/target/classes/com/stdproject/service/impl/AppOptLogServiceImpl.class b/backend/target/classes/com/stdproject/service/impl/AppOptLogServiceImpl.class new file mode 100644 index 0000000..94c1516 Binary files /dev/null and b/backend/target/classes/com/stdproject/service/impl/AppOptLogServiceImpl.class differ diff --git a/backend/target/classes/com/stdproject/service/impl/AppOrganizationServiceImpl.class b/backend/target/classes/com/stdproject/service/impl/AppOrganizationServiceImpl.class new file mode 100644 index 0000000..e0b54bf Binary files /dev/null and b/backend/target/classes/com/stdproject/service/impl/AppOrganizationServiceImpl.class differ diff --git a/backend/target/classes/com/stdproject/service/impl/AppRoleMenuServiceImpl.class b/backend/target/classes/com/stdproject/service/impl/AppRoleMenuServiceImpl.class new file mode 100644 index 0000000..1db363d Binary files /dev/null and b/backend/target/classes/com/stdproject/service/impl/AppRoleMenuServiceImpl.class differ diff --git a/backend/target/classes/com/stdproject/service/impl/AppRoleServiceImpl.class b/backend/target/classes/com/stdproject/service/impl/AppRoleServiceImpl.class new file mode 100644 index 0000000..2a6e664 Binary files /dev/null and b/backend/target/classes/com/stdproject/service/impl/AppRoleServiceImpl.class differ diff --git a/backend/target/classes/com/stdproject/service/impl/AppRoleUserServiceImpl.class b/backend/target/classes/com/stdproject/service/impl/AppRoleUserServiceImpl.class new file mode 100644 index 0000000..df6f53e Binary files /dev/null and b/backend/target/classes/com/stdproject/service/impl/AppRoleUserServiceImpl.class differ diff --git a/backend/target/classes/com/stdproject/service/impl/AppUserServiceImpl.class b/backend/target/classes/com/stdproject/service/impl/AppUserServiceImpl.class new file mode 100644 index 0000000..434ba4b Binary files /dev/null and b/backend/target/classes/com/stdproject/service/impl/AppUserServiceImpl.class differ diff --git a/backend/target/classes/com/stdproject/utils/CaptchaUtils$CaptchaResult.class b/backend/target/classes/com/stdproject/utils/CaptchaUtils$CaptchaResult.class new file mode 100644 index 0000000..4f48d8d Binary files /dev/null and b/backend/target/classes/com/stdproject/utils/CaptchaUtils$CaptchaResult.class differ diff --git a/backend/target/classes/com/stdproject/utils/CaptchaUtils.class b/backend/target/classes/com/stdproject/utils/CaptchaUtils.class new file mode 100644 index 0000000..45f5ffc Binary files /dev/null and b/backend/target/classes/com/stdproject/utils/CaptchaUtils.class differ diff --git a/backend/target/classes/com/stdproject/utils/FileUtils.class b/backend/target/classes/com/stdproject/utils/FileUtils.class new file mode 100644 index 0000000..7bdc4b7 Binary files /dev/null and b/backend/target/classes/com/stdproject/utils/FileUtils.class differ diff --git a/backend/target/classes/com/stdproject/utils/JwtUtils$ClaimsResolver.class b/backend/target/classes/com/stdproject/utils/JwtUtils$ClaimsResolver.class new file mode 100644 index 0000000..9b15550 Binary files /dev/null and b/backend/target/classes/com/stdproject/utils/JwtUtils$ClaimsResolver.class differ diff --git a/backend/target/classes/com/stdproject/utils/JwtUtils.class b/backend/target/classes/com/stdproject/utils/JwtUtils.class new file mode 100644 index 0000000..49d3b08 Binary files /dev/null and b/backend/target/classes/com/stdproject/utils/JwtUtils.class differ diff --git a/backend/target/classes/com/stdproject/utils/PasswordUtils.class b/backend/target/classes/com/stdproject/utils/PasswordUtils.class new file mode 100644 index 0000000..a68da54 Binary files /dev/null and b/backend/target/classes/com/stdproject/utils/PasswordUtils.class differ diff --git a/backend/target/classes/ehcache.xml b/backend/target/classes/ehcache.xml new file mode 100644 index 0000000..0c9ff84 --- /dev/null +++ b/backend/target/classes/ehcache.xml @@ -0,0 +1,58 @@ + + + + + + 3600 + + + 1000 + 10 + + + + + + + 30 + + + + + + + 60 + + + + + + + 60 + + + + + + + 60 + + + + + + + 2 + + + + + + + 1 + + + + \ No newline at end of file diff --git a/backend/target/classes/logback-spring.xml b/backend/target/classes/logback-spring.xml new file mode 100644 index 0000000..43814d0 --- /dev/null +++ b/backend/target/classes/logback-spring.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + + + + ${LOG_PATH}/info.log + + ${LOG_PATH}/info.%d{yyyy-MM-dd}.log + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + INFO + ACCEPT + DENY + + + + + ${LOG_PATH}/error.log + + ${LOG_PATH}/error.%d{yyyy-MM-dd}.log + 30 + + + %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + UTF-8 + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..f221e12 --- /dev/null +++ b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,71 @@ +com\stdproject\common\DataPermission.class +com\stdproject\service\IAppRoleUserService.class +com\stdproject\controller\AppMenuController$MenuOrderRequest.class +com\stdproject\service\impl\AppRoleUserServiceImpl.class +com\stdproject\config\SwaggerConfig.class +com\stdproject\controller\AppUserController$PasswordUpdateRequest.class +com\stdproject\service\IAppUserService.class +com\stdproject\controller\AppUserController.class +com\stdproject\controller\AppOptLogController$LogStatistics.class +com\stdproject\controller\AppDictionaryController.class +com\stdproject\entity\AppUser.class +com\stdproject\entity\AppRoleMenu.class +com\stdproject\entity\AppRoleUser.class +com\stdproject\config\WebConfig.class +com\stdproject\entity\AppOptLog.class +com\stdproject\service\IAppDictionaryService.class +com\stdproject\controller\AppOptLogController.class +com\stdproject\service\IAppRoleMenuService.class +com\stdproject\StdProjectApplication.class +com\stdproject\config\CustomUserDetailsService.class +com\stdproject\service\impl\AppDictionaryServiceImpl.class +com\stdproject\service\impl\AppRoleMenuServiceImpl.class +com\stdproject\service\IAppOptLogService.class +com\stdproject\controller\AppRoleController.class +com\stdproject\controller\AuthController$ChangePasswordRequest.class +com\stdproject\service\impl\AppOrganizationServiceImpl.class +com\stdproject\common\Result.class +com\stdproject\mapper\AppMenuMapper.class +com\stdproject\mapper\AppOptLogMapper.class +com\stdproject\config\JwtAuthenticationEntryPoint.class +com\stdproject\controller\AuthController.class +com\stdproject\utils\CaptchaUtils$CaptchaResult.class +com\stdproject\controller\AppMenuController$MenuTreeNode.class +com\stdproject\common\Constants.class +com\stdproject\common\OperationLogAspect.class +com\stdproject\service\impl\AppOptLogServiceImpl.class +com\stdproject\utils\JwtUtils$ClaimsResolver.class +com\stdproject\utils\CaptchaUtils.class +com\stdproject\common\OperationLog.class +com\stdproject\service\IAppRoleService.class +com\stdproject\common\BusinessException.class +com\stdproject\service\impl\AppMenuServiceImpl.class +com\stdproject\utils\PasswordUtils.class +com\stdproject\entity\AppDictionary.class +com\stdproject\utils\FileUtils.class +com\stdproject\service\impl\AppRoleServiceImpl.class +com\stdproject\utils\JwtUtils.class +com\stdproject\controller\AuthController$LoginRequest.class +com\stdproject\entity\AppRole.class +com\stdproject\common\ResultCode.class +com\stdproject\controller\AppOrganizationController.class +com\stdproject\mapper\AppRoleUserMapper.class +com\stdproject\controller\AppUserController$PasswordResetRequest.class +com\stdproject\mapper\AppRoleMapper.class +com\stdproject\service\IAppOrganizationService.class +com\stdproject\config\SecurityConfig.class +com\stdproject\controller\AppMenuController.class +com\stdproject\mapper\AppOrganizationMapper.class +com\stdproject\mapper\AppDictionaryMapper.class +com\stdproject\entity\AppOrganization.class +com\stdproject\config\JwtAuthenticationFilter.class +com\stdproject\mapper\AppUserMapper.class +com\stdproject\entity\AppMenu.class +com\stdproject\common\PageRequest.class +com\stdproject\controller\AppDictionaryController$DictOrderRequest.class +com\stdproject\service\impl\AppUserServiceImpl.class +com\stdproject\config\MybatisPlusConfig.class +com\stdproject\mapper\AppRoleMenuMapper.class +com\stdproject\common\GlobalExceptionHandler.class +com\stdproject\service\IAppMenuService.class +com\stdproject\config\CacheConfig.class diff --git a/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..7c508f1 --- /dev/null +++ b/backend/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,61 @@ +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\JwtAuthenticationFilter.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppDictionaryService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppOrganizationMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\utils\PasswordUtils.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppOrganizationServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppOptLogController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\MybatisPlusConfig.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppUser.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppDictionaryMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\SecurityConfig.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\SwaggerConfig.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\DataPermission.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppMenuService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\ResultCode.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppMenuServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppRole.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppOrganization.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppRoleController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppRoleMenuServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppRoleServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppRoleMenu.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppOptLog.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppRoleMenuMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppRoleUserMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\PageRequest.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppOptLogMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppOrganizationController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppUserController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppDictionaryServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppOptLogService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\BusinessException.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppUserServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppUserService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\utils\FileUtils.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\utils\JwtUtils.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\CacheConfig.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppRoleMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\WebConfig.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\Constants.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppRoleUser.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\OperationLogAspect.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppMenu.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppUserMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\JwtAuthenticationEntryPoint.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\entity\AppDictionary.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppRoleService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\utils\CaptchaUtils.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppRoleUserService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppMenuController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppOrganizationService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\IAppRoleMenuService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\GlobalExceptionHandler.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\OperationLog.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AppDictionaryController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppOptLogServiceImpl.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\StdProjectApplication.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\controller\AuthController.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\common\Result.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\config\CustomUserDetailsService.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\mapper\AppMenuMapper.java +D:\Trae_space\StdProject\backend\src\main\java\com\stdproject\service\impl\AppRoleUserServiceImpl.java diff --git a/dev-prompt.md b/dev-prompt.md new file mode 100644 index 0000000..0183689 --- /dev/null +++ b/dev-prompt.md @@ -0,0 +1,152 @@ +# 开发一个标准的JavaSpringboot应用项目 +## 项目采用如下技术框架: +## 1. 后端采用最新的Springboot3.0框架。 +## 2. 数据库采用MySQL8.0数据库,使用MyBatis-Plus框架进行数据库操作。 + 数据库配置如下: + url: jdbc:mysql://121.37.111.42:3306/gisbi-demodb?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai + username: root + password: mysql_F8ysiK@2024 +## 3. 前端采用Vue3.0框架,使用Element-Plus组件库。 +## 4. 项目采用Git进行版本控制,使用Maven进行项目管理。 +## 5. 项目采用Docker进行容器化部署,使用Jenkins进行自动化部署。 +## 6. 项目采用Swagger进行API文档管理,使用Postman进行API测试。 +## 7.系统使用JWT进行用户认证和授权,采用spring配置参数进行是否此案有token访问认证的控制,默认进行认证控制。 +## 8.spring采用jcache进行缓存管理。 +## 9.项目采用logback进行日志配置和管理。 + +## 项目实现如下基础框架功能: +### 组织管理:包括组织添加、组织修改、组织删除、组织查询等功能。(组织是一个结构树:含公司和部门两级) +CREATE TABLE `app_organization` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `orgtype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '组织类型:01-公司 02-部门', + `orgcode` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '组织编号', + `orgname` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '组织名称', + `parentid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '上级ID', + `manager` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '组织负责人', + `description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '组织详情', + `address` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '联系地址', + `contact_phone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '联系电话', + `contact_person` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '联系人', + `isvaild` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '是否有效 1-是 0-否', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='应用系统_用户组织'; +### 用户管理:包括用用户信息维护、用户角色分配、用户登录、用户修改密码、用户修改个人信息等功能。 +CREATE TABLE `app_user` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `orgid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '所属组织', + `usertype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户类型 0-管理员 1-普通用户', + `username` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户名称 用户名称(账号)', + `nickname` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户昵称(中文)', + `password` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '登录密码', + `email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '邮箱', + `phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '手机号', + `avatar` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '用户头像 base64存储用户头像', + `status` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '1' COMMENT '状态 1-有效 0-停用', + `pwdvalidperiod` int DEFAULT '90' COMMENT '密码有限期 密码有限期(天)', + `failednum` int DEFAULT '0' COMMENT '登录失败次数 允许的登录失败次数', + `loginip` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户指定登录IP 如果设置了IP,则只允许IP用户登录', + `failedlocktime` datetime DEFAULT NULL COMMENT '登录失败锁定时间', + `pwdresettime` datetime DEFAULT NULL COMMENT '密码修改时间', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='应用系统_系统用户'; + +CREATE TABLE `app_role_users` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `roleid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色id', + `userid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='系统角色-用户对照'; + +### 角色管理:包括角色添加、角色修改、角色删除、角色查询,角色权限分配等功能。 +CREATE TABLE `app_role` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `rolecode` varchar(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色编号 系统生成,三位编号', + `rolename` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色名称', + `type` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色类别 1-应用管理员 2-应用普通用户', + `description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '角色描述', + `isvaild` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '1' COMMENT '是否有效 1-是 0-否', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '最近修改者', + `lastmodifydate` datetime NOT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='应用系统_系统角色'; + + +### 权限管理:包括角色菜单权限添加、权限修改、权限删除、权限查询等功能。 +CREATE TABLE `app_role_menu` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `roleid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色id', + `menuid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单id', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='系统角色-数据权限对照'; + +### 菜单管理:包括菜单添加、菜单修改、菜单删除、菜单查询等功能。 +CREATE TABLE `app_menu` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'ID', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `type` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单类型 01-菜单', + `code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单编号', + `orderno` int DEFAULT NULL COMMENT '同级序号', + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '菜单名称', + `icon` varchar(9000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '菜单图标 base64存储', + `islink` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '是否外链 0-非外部 1-是外链', + `url` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '菜单URL 内部资源页面URL访问地址', + `module_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '模块ID 菜单关联的模块ID', + `parentid` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '父级菜单ID 顶级为0', + `isdisplay` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '是否显示 0-不显示 1-显示', + `lastmodifier` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '最近修改者', + `lastmodifydate` datetime DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='应用系统_菜单'; + +### 日志管理:包括登录日志、操作日志等插入,查询功能。 +CREATE TABLE `app_optlog` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `usercode` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户账号', + `username` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户名称', + `opttype` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '操作类型 00-登录 01-新增 02-修改 03-删除 06-查询 09其他', + `module` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '模块名称', + `description` varchar(400) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '日志描述', + `method` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '操作方法', + `params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin COMMENT '方法参数', + `logtime` datetime DEFAULT NULL COMMENT '创建时间', + `requestip` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '请求IP', + `browser` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '浏览器类型', + PRIMARY KEY (`id`), + KEY `log_create_time_index` (`logtime`) USING BTREE, + KEY `inx_log_type` (`opttype`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='系统操作日志'; +### 数据字典:包括数据字典添加、数据字典修改、数据字典删除、数据字典查询等功能。 +CREATE TABLE `app_dictionary` ( + `id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'id', + `app_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '应用ID 关联应用系统', + `orderno` int NOT NULL COMMENT '顺序号', + `dictcode` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典编码', + `dictname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '字典名称', + `dictdata` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '字典数据 JSON数组[{"code":"01","name":"字典值"}]', + `lastmodifydate` datetime DEFAULT NULL COMMENT '最近修改日期', + `custom1` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用1', + `custom2` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用2', + `custom3` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备用3', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='应用-数据字典'; diff --git a/logs/stdproject-backend/error.2025-05-29.log b/logs/stdproject-backend/error.2025-05-29.log new file mode 100644 index 0000000..4e3e99a --- /dev/null +++ b/logs/stdproject-backend/error.2025-05-29.log @@ -0,0 +1,26 @@ +2025-05-29 18:19:01.061 [main] ERROR o.s.b.w.e.tomcat.TomcatStarter - Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'jwtAuthenticationFilter': Unsatisfied dependency expressed through field 'userDetailsService': Error creating bean with name 'customUserDetailsService': Unsatisfied dependency expressed through field 'appUserService': Error creating bean with name 'appUserServiceImpl': Unsatisfied dependency expressed through field 'passwordEncoder': Error creating bean with name 'securityConfig' defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\config\SecurityConfig.class]: Unsatisfied dependency expressed through constructor parameter 1: Error creating bean with name 'jwtAuthenticationFilter': Requested bean is currently in creation: Is there an unresolvable circular reference? +2025-05-29 18:19:01.139 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +The dependencies of some of the beans in the application context form a cycle: + +┌─────┐ +| jwtAuthenticationFilter (field private org.springframework.security.core.userdetails.UserDetailsService com.stdproject.config.JwtAuthenticationFilter.userDetailsService) +↑ ↓ +| customUserDetailsService (field private com.stdproject.service.IAppUserService com.stdproject.config.CustomUserDetailsService.appUserService) +↑ ↓ +| appUserServiceImpl (field private org.springframework.security.crypto.password.PasswordEncoder com.stdproject.service.impl.AppUserServiceImpl.passwordEncoder) +↑ ↓ +| securityConfig defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\config\SecurityConfig.class] +└─────┘ + + +Action: + +Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true. + diff --git a/logs/stdproject-backend/error.log b/logs/stdproject-backend/error.log new file mode 100644 index 0000000..047f72f --- /dev/null +++ b/logs/stdproject-backend/error.log @@ -0,0 +1,1729 @@ +2025-05-30 09:04:27.397 [main] ERROR o.s.b.w.e.tomcat.TomcatStarter - Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'jwtAuthenticationFilter': Unsatisfied dependency expressed through field 'userDetailsService': Error creating bean with name 'customUserDetailsService': Unsatisfied dependency expressed through field 'appUserService': Error creating bean with name 'appUserServiceImpl': Unsatisfied dependency expressed through field 'passwordEncoder': Error creating bean with name 'securityConfig' defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\config\SecurityConfig.class]: Unsatisfied dependency expressed through constructor parameter 1: Error creating bean with name 'jwtAuthenticationFilter': Requested bean is currently in creation: Is there an unresolvable circular reference? +2025-05-30 09:04:27.470 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +The dependencies of some of the beans in the application context form a cycle: + +┌─────┐ +| jwtAuthenticationFilter (field private org.springframework.security.core.userdetails.UserDetailsService com.stdproject.config.JwtAuthenticationFilter.userDetailsService) +↑ ↓ +| customUserDetailsService (field private com.stdproject.service.IAppUserService com.stdproject.config.CustomUserDetailsService.appUserService) +↑ ↓ +| appUserServiceImpl (field private org.springframework.security.crypto.password.PasswordEncoder com.stdproject.service.impl.AppUserServiceImpl.passwordEncoder) +↑ ↓ +| securityConfig defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\config\SecurityConfig.class] +└─────┘ + + +Action: + +Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true. + +2025-05-30 09:08:43.941 [main] ERROR o.s.boot.SpringApplication - Application run failed +org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Ambiguous mapping. Cannot map 'appOrganizationController' method +com.stdproject.controller.AppOrganizationController#add(AppOrganization) +to {POST [/api/org]}: There is already 'appOrganizationController' bean method +com.stdproject.controller.AppOrganizationController#update(AppOrganization) mapped. + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1751) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) + at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) + at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) + at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) + at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) + at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961) + at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915) + at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584) + at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) + at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730) + at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302) + at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291) + at com.stdproject.ProjectApplication.main(ProjectApplication.java:24) +Caused by: java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'appOrganizationController' method +com.stdproject.controller.AppOrganizationController#add(AppOrganization) +to {POST [/api/org]}: There is already 'appOrganizationController' bean method +com.stdproject.controller.AppOrganizationController#update(AppOrganization) mapped. + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.validateMethodMapping(AbstractHandlerMethodMapping.java:667) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$MappingRegistry.register(AbstractHandlerMethodMapping.java:633) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod(AbstractHandlerMethodMapping.java:331) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(RequestMappingHandlerMapping.java:438) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.registerHandlerMethod(RequestMappingHandlerMapping.java:76) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lambda$detectHandlerMethods$2(AbstractHandlerMethodMapping.java:298) + at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:986) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(AbstractHandlerMethodMapping.java:296) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.processCandidateBean(AbstractHandlerMethodMapping.java:265) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.java:224) + at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.java:212) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.java:225) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1797) + at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1747) + ... 16 common frames omitted +2025-05-30 09:20:20.924 [main] ERROR o.s.b.w.e.tomcat.TomcatStarter - Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'jwtAuthenticationFilter': Unsatisfied dependency expressed through field 'userDetailsService': Error creating bean with name 'customUserDetailsService': Unsatisfied dependency expressed through field 'appUserService': Error creating bean with name 'appUserServiceImpl': Unsatisfied dependency expressed through field 'baseMapper': Error creating bean with name 'appUserMapper' defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\mapper\AppUserMapper.class]: Unsatisfied dependency expressed through bean property 'sqlSessionFactory': Error creating bean with name 'sqlSessionFactory' defined in class path resource [com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.class]: Unsatisfied dependency expressed through method 'sqlSessionFactory' parameter 0: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception with message: Failed to determine a suitable driver class +2025-05-30 09:20:21.059 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. + +Reason: Failed to determine a suitable driver class + + +Action: + +Consider the following: + If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. + If you have database settings to be loaded from a particular profile you may need to activate it (the profiles dev are currently active). + +2025-05-30 09:20:22.684 [main] ERROR o.s.b.w.e.tomcat.TomcatStarter - Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'jwtAuthenticationFilter': Unsatisfied dependency expressed through field 'userDetailsService': Error creating bean with name 'customUserDetailsService': Unsatisfied dependency expressed through field 'appUserService': Error creating bean with name 'appUserServiceImpl': Unsatisfied dependency expressed through field 'baseMapper': Error creating bean with name 'appUserMapper' defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\mapper\AppUserMapper.class]: Unsatisfied dependency expressed through bean property 'sqlSessionFactory': Error creating bean with name 'sqlSessionFactory' defined in class path resource [com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.class]: Unsatisfied dependency expressed through method 'sqlSessionFactory' parameter 0: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception with message: Failed to determine a suitable driver class +2025-05-30 09:20:22.811 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. + +Reason: Failed to determine a suitable driver class + + +Action: + +Consider the following: + If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. + If you have database settings to be loaded from a particular profile you may need to activate it (the profiles dev are currently active). + +2025-05-30 09:21:40.470 [main] ERROR o.s.b.w.e.tomcat.TomcatStarter - Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'jwtAuthenticationFilter': Unsatisfied dependency expressed through field 'userDetailsService': Error creating bean with name 'customUserDetailsService': Unsatisfied dependency expressed through field 'appUserService': Error creating bean with name 'appUserServiceImpl': Unsatisfied dependency expressed through field 'baseMapper': Error creating bean with name 'appUserMapper' defined in file [D:\Trae_space\StdProject\backend\target\classes\com\stdproject\mapper\AppUserMapper.class]: Unsatisfied dependency expressed through bean property 'sqlSessionFactory': Error creating bean with name 'sqlSessionFactory' defined in class path resource [com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.class]: Unsatisfied dependency expressed through method 'sqlSessionFactory' parameter 0: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception with message: Failed to determine a suitable driver class +2025-05-30 09:21:40.606 [main] ERROR o.s.b.d.LoggingFailureAnalysisReporter - + +*************************** +APPLICATION FAILED TO START +*************************** + +Description: + +Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured. + +Reason: Failed to determine a suitable driver class + + +Action: + +Consider the following: + If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. + If you have database settings to be loaded from a particular profile you may need to activate it (the profiles dev are currently active). + +2025-05-30 09:28:01.120 [http-nio-8080-exec-6] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:28:24.799 [http-nio-8080-exec-8] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:31:20.228 [http-nio-8080-exec-9] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:34:02.397 [http-nio-8080-exec-10] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:35:32.114 [http-nio-8080-exec-1] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:38:07.965 [http-nio-8080-exec-2] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:38:29.326 [http-nio-8080-exec-3] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:39:37.992 [http-nio-8080-exec-1] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy141.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy138.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy137.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted +2025-05-30 09:44:35.995 [http-nio-8080-exec-6] ERROR c.s.common.GlobalExceptionHandler - 运行时异常: /api/role - Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null +org.springframework.dao.InvalidDataAccessApiUsageException: Error attempting to get column 'lastmodifydate' from result set. Cause: java.sql.SQLFeatureNotSupportedException +; null + at org.springframework.jdbc.support.SQLExceptionSubclassTranslator.doTranslate(SQLExceptionSubclassTranslator.java:96) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:70) + at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:79) + at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:91) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441) + at jdk.proxy2/jdk.proxy2.$Proxy88.selectList(Unknown Source) + at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForMany(MybatisMapperMethod.java:166) + at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:77) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectList(Unknown Source) + at com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(BaseMapper.java:172) + at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:733) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$DefaultMethodInvoker.invoke(MybatisMapperProxy.java:162) + at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) + at jdk.proxy2/jdk.proxy2.$Proxy93.selectOne(Unknown Source) + at com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne(ServiceImpl.java:202) + at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:320) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:699) + at com.stdproject.service.impl.AppRoleServiceImpl$$SpringCGLIB$$0.getOne() + at com.stdproject.controller.AppRoleController.save(AppRoleController.java:112) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) + at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) + at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) + at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:752) + at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:703) + at com.stdproject.controller.AppRoleController$$SpringCGLIB$$0.save() + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207) + at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152) + at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884) + at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) + at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) + at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1080) + at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:973) + at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1003) + at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:906) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:731) + at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:880) + at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:814) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:223) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at com.stdproject.config.JwtAuthenticationFilter.doFilterInternal(JwtAuthenticationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.security.web.FilterChainProxy.lambda$doFilterInternal$3(FilterChainProxy.java:231) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:365) + at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:126) + at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:120) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:131) + at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:85) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:100) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:179) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:151) + at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:129) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:107) + at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:93) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) + at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.SecurityContextHolderFilter.doFilterInternal(SecurityContextHolderFilter.java:69) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:62) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:374) + at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:233) + at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:191) + at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:351) + at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) + at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) + at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:185) + at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:158) + at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) + at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) + at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542) + at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:119) + at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) + at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) + at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) + at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:400) + at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) + at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:861) + at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1739) + at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) + at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) + at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) + at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) + at java.base/java.lang.Thread.run(Thread.java:1583) +Caused by: java.sql.SQLFeatureNotSupportedException: null + at org.sqlite.jdbc4.JDBC4ResultSet.getObject(JDBC4ResultSet.java:343) + at com.zaxxer.hikari.pool.HikariProxyResultSet.getObject(HikariProxyResultSet.java) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.logging.jdbc.ResultSetLogger.invoke(ResultSetLogger.java:69) + at jdk.proxy3/jdk.proxy3.$Proxy155.getObject(Unknown Source) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:38) + at org.apache.ibatis.type.LocalDateTimeTypeHandler.getNullableResult(LocalDateTimeTypeHandler.java:28) + at org.apache.ibatis.type.BaseTypeHandler.getResult(BaseTypeHandler.java:85) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyAutomaticMappings(DefaultResultSetHandler.java:572) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:409) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308) + at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201) + at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) + at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64) + at jdk.proxy2/jdk.proxy2.$Proxy152.query(Unknown Source) + at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) + at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) + at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) + at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) + at com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor.intercept(MybatisPlusInterceptor.java:81) + at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) + at jdk.proxy2/jdk.proxy2.$Proxy151.query(Unknown Source) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) + at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) + ... 133 common frames omitted diff --git a/logs/stdproject-backend/info.2025-05-29.log b/logs/stdproject-backend/info.2025-05-29.log new file mode 100644 index 0000000..833c6c1 --- /dev/null +++ b/logs/stdproject-backend/info.2025-05-29.log @@ -0,0 +1,11 @@ +2025-05-29 18:18:57.837 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 31224 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-29 18:18:57.841 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-29 18:19:00.260 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-29 18:19:00.292 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-29 18:19:00.293 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-29 18:19:00.411 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-29 18:19:00.414 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2493 ms +2025-05-29 18:19:01.091 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] +2025-05-29 18:19:01.112 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. diff --git a/logs/stdproject-backend/info.log b/logs/stdproject-backend/info.log new file mode 100644 index 0000000..2f9b8b2 --- /dev/null +++ b/logs/stdproject-backend/info.log @@ -0,0 +1,121 @@ +2025-05-30 09:04:24.751 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 10576 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:04:24.764 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:04:26.767 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:04:26.793 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:04:26.793 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:04:26.897 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:04:26.899 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2078 ms +2025-05-30 09:04:27.429 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] +2025-05-30 09:04:27.444 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2025-05-30 09:08:39.077 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 23288 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:08:39.081 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:08:41.425 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:08:41.446 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:08:41.446 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:08:41.569 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:08:41.571 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2420 ms +2025-05-30 09:08:43.882 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] +2025-05-30 09:08:43.909 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2025-05-30 09:11:19.221 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 25020 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:11:19.226 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:11:21.600 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:11:21.635 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:11:21.636 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:11:21.759 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:11:21.761 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2465 ms +2025-05-30 09:11:25.139 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '' +2025-05-30 09:11:25.156 [main] INFO com.stdproject.ProjectApplication - Started ProjectApplication in 6.759 seconds (process running for 7.313) +2025-05-30 09:11:32.236 [http-nio-8080-exec-2] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet' +2025-05-30 09:11:32.238 [http-nio-8080-exec-2] INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet' +2025-05-30 09:11:32.241 [http-nio-8080-exec-2] INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 3 ms +2025-05-30 09:11:35.704 [http-nio-8080-exec-1] INFO o.s.api.AbstractOpenApiResource - Init duration for springdoc-openapi is: 1859 ms +2025-05-30 09:20:16.890 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 26052 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:20:16.895 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:20:19.377 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 5732 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:20:19.382 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:20:20.430 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:20:20.459 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:20:20.460 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:20:20.606 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:20:20.609 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 3639 ms +2025-05-30 09:20:20.978 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] +2025-05-30 09:20:21.022 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2025-05-30 09:20:22.281 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:20:22.298 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:20:22.298 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:20:22.423 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:20:22.425 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2944 ms +2025-05-30 09:20:22.725 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] +2025-05-30 09:20:22.769 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2025-05-30 09:21:37.663 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 24096 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:21:37.667 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:21:40.072 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:21:40.093 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:21:40.093 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:21:40.208 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:21:40.210 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2474 ms +2025-05-30 09:21:40.522 [main] INFO o.a.catalina.core.StandardService - Stopping service [Tomcat] +2025-05-30 09:21:40.559 [main] INFO o.s.b.a.l.ConditionEvaluationReportLogger - + +Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. +2025-05-30 09:23:12.391 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 10440 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:23:12.396 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:23:14.831 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:23:14.866 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:23:14.867 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:23:14.996 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:23:14.999 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2524 ms +2025-05-30 09:23:18.657 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '' +2025-05-30 09:23:18.676 [main] INFO com.stdproject.ProjectApplication - Started ProjectApplication in 7.149 seconds (process running for 7.707) +2025-05-30 09:23:29.855 [http-nio-8080-exec-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet' +2025-05-30 09:23:29.855 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet' +2025-05-30 09:23:29.858 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 3 ms +2025-05-30 09:23:32.585 [http-nio-8080-exec-9] INFO o.s.api.AbstractOpenApiResource - Init duration for springdoc-openapi is: 1406 ms +2025-05-30 09:25:46.231 [http-nio-8080-exec-4] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Starting... +2025-05-30 09:25:53.371 [http-nio-8080-exec-4] INFO com.zaxxer.hikari.pool.HikariPool - StdProjectHikariCP - Added connection org.sqlite.jdbc4.JDBC4Connection@257e98f5 +2025-05-30 09:25:53.378 [http-nio-8080-exec-4] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Start completed. +2025-05-30 09:38:29.381 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Shutdown initiated... +2025-05-30 09:38:29.384 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Shutdown completed. +2025-05-30 09:38:59.919 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 16828 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:38:59.923 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:39:02.296 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:39:02.317 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:39:02.317 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:39:02.463 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:39:02.465 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2474 ms +2025-05-30 09:39:05.970 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '' +2025-05-30 09:39:05.988 [main] INFO com.stdproject.ProjectApplication - Started ProjectApplication in 6.857 seconds (process running for 7.374) +2025-05-30 09:39:10.552 [http-nio-8080-exec-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet' +2025-05-30 09:39:10.552 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet' +2025-05-30 09:39:10.553 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 1 ms +2025-05-30 09:39:14.268 [http-nio-8080-exec-1] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Starting... +2025-05-30 09:39:21.058 [http-nio-8080-exec-1] INFO com.zaxxer.hikari.pool.HikariPool - StdProjectHikariCP - Added connection org.sqlite.jdbc4.JDBC4Connection@2d58c582 +2025-05-30 09:39:21.066 [http-nio-8080-exec-1] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Start completed. +2025-05-30 09:40:03.946 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Shutdown initiated... +2025-05-30 09:40:03.949 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Shutdown completed. +2025-05-30 09:41:36.750 [main] INFO com.stdproject.ProjectApplication - Starting ProjectApplication using Java 21.0.5 with PID 6824 (D:\Trae_space\StdProject\backend\target\classes started by zhengsl in D:\Trae_space\StdProject) +2025-05-30 09:41:36.754 [main] INFO com.stdproject.ProjectApplication - The following 1 profile is active: "dev" +2025-05-30 09:41:38.891 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http) +2025-05-30 09:41:38.930 [main] INFO o.a.catalina.core.StandardService - Starting service [Tomcat] +2025-05-30 09:41:38.930 [main] INFO o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.1] +2025-05-30 09:41:39.052 [main] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext +2025-05-30 09:41:39.054 [main] INFO o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 2232 ms +2025-05-30 09:41:42.481 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path '' +2025-05-30 09:41:42.495 [main] INFO com.stdproject.ProjectApplication - Started ProjectApplication in 6.508 seconds (process running for 6.944) +2025-05-30 09:41:46.298 [http-nio-8080-exec-1] INFO o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet' +2025-05-30 09:41:46.298 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet' +2025-05-30 09:41:46.301 [http-nio-8080-exec-1] INFO o.s.web.servlet.DispatcherServlet - Completed initialization in 3 ms +2025-05-30 09:41:48.874 [http-nio-8080-exec-9] INFO o.s.api.AbstractOpenApiResource - Init duration for springdoc-openapi is: 1406 ms +2025-05-30 09:43:25.735 [http-nio-8080-exec-4] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Starting... +2025-05-30 09:43:32.947 [http-nio-8080-exec-4] INFO com.zaxxer.hikari.pool.HikariPool - StdProjectHikariCP - Added connection org.sqlite.jdbc4.JDBC4Connection@23aa73a5 +2025-05-30 09:43:32.960 [http-nio-8080-exec-4] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Start completed. +2025-05-30 09:47:30.964 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Shutdown initiated... +2025-05-30 09:47:30.966 [SpringApplicationShutdownHook] INFO com.zaxxer.hikari.HikariDataSource - StdProjectHikariCP - Shutdown completed. diff --git a/projectframe.md b/projectframe.md new file mode 100644 index 0000000..78b19d8 --- /dev/null +++ b/projectframe.md @@ -0,0 +1,28 @@ +StdProject/ +├── backend/ # Spring Boot 后端 +│ ├── src/main/java/ +│ │ └── com/stdproject/ # 包名(com.stdproject) +│ │ ├── StdProjectApplication.java +│ │ ├── config/ # 配置类 +│ │ ├── controller/ # 控制器 +│ │ ├── service/ # 服务层 +│ │ ├── mapper/ # MyBatis映射器 +│ │ ├── entity/ # 实体类 +│ │ ├── common/ # 通用类 +│ │ └── utils/ # 工具类 +│ ├── src/main/resources/ +│ │ ├── application.yml +│ │ ├── logback-spring.xml +│ │ └── mapper/ +│ └── pom.xml +├── frontend/ # Vue3 前端 +│ ├── src/ +│ │ ├── components/ +│ │ ├── views/ +│ │ ├── router/ +│ │ ├── store/ +│ │ ├── utils/ +│ │ └── api/ +│ ├── package.json +│ └── vite.config.js +└── docker-compose.yml # Docker部署配置 \ No newline at end of file