Initial commit of backend project

This commit is contained in:
wangzhiwei 2026-01-22 10:20:02 +08:00
commit 3d6accfd5d
254 changed files with 78766 additions and 0 deletions

48
.gitignore vendored Normal file
View File

@ -0,0 +1,48 @@
# Maven target directory
target/
# IDEA files
.idea/
*.iml
*.iws
# Eclipse files
.project
.classpath
.settings/
# Log files
logs/
*.log
nohup.out
# OS files
.DS_Store
Thumbs.db
# Temporary files
*.swp
*.swo
# Build files
*.jar
*.war
# Environment files
.env
.env.local
.env.*.local
# Database files
*.db
*.sqlite
# Test reports
surefire-reports/
jacoco/
# Maven wrapper
.mvn/wrapper/maven-wrapper.jar
# App directory (contains compiled jar and scripts)
app/

1
.mvn/wrapper/maven-wrapper.properties vendored Normal file
View File

@ -0,0 +1 @@
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar

5
Dockerfile Normal file
View File

@ -0,0 +1,5 @@
FROM openjdk:8-jdk-alpine
MAINTAINER kexue
VOLUME /tmp
ADD target/hyxp-portal.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

312
db/create_tables.sql Normal file
View File

@ -0,0 +1,312 @@
-- 创建数据库表结构
-- 作者: 王志维
-- 创建时间: 2026-01-20
-- 设置字符集
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- 1. 账户表
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account` (
`account_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`user_name` varchar(50) DEFAULT NULL COMMENT '用户名',
`balance` decimal(10,2) DEFAULT '0.00' COMMENT '账户余额',
`frozen_amount` decimal(10,2) DEFAULT '0.00' COMMENT '冻结金额',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`delete_flag` tinyint(1) DEFAULT '0' COMMENT '是否删除 0 未删除1已删除',
PRIMARY KEY (`account_id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='账户表,记录用户的账户信息';
-- 2. 账户流水表
DROP TABLE IF EXISTS `account_transaction`;
CREATE TABLE `account_transaction` (
`transaction_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`user_name` varchar(50) DEFAULT NULL COMMENT '用户名',
`transaction_type` tinyint(1) NOT NULL COMMENT '交易类型1.充值 2.提现 3.购买内容 4.退款 5.其他',
`amount` decimal(10,2) NOT NULL COMMENT '交易金额',
`before_balance` decimal(10,2) NOT NULL COMMENT '交易前余额',
`after_balance` decimal(10,2) NOT NULL COMMENT '交易后余额',
`status` tinyint(1) NOT NULL COMMENT '交易状态1.成功 2.失败 3.处理中',
`transaction_no` varchar(50) NOT NULL COMMENT '交易单号',
`pay_type` tinyint(1) DEFAULT NULL COMMENT '支付方式1.微信 2.支付宝 3.余额支付',
`business_id` bigint(20) DEFAULT NULL COMMENT '关联业务ID',
`business_type` varchar(50) DEFAULT NULL COMMENT '业务类型',
`remark` varchar(255) DEFAULT NULL COMMENT '交易备注',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
`update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
`delete_flag` tinyint(1) DEFAULT '0' COMMENT '是否删除 0 未删除1已删除',
PRIMARY KEY (`transaction_id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_transaction_no` (`transaction_no`),
KEY `idx_business_id` (`business_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='账户流水表,记录用户的账户交易记录';
-- 3. 积分账户表
DROP TABLE IF EXISTS `points_account`;
CREATE TABLE `points_account` (
`account_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`user_name` varchar(50) DEFAULT NULL COMMENT '用户名',
`total_points` int(11) DEFAULT '0' COMMENT '总积分',
`available_points` int(11) DEFAULT '0' COMMENT '可用积分',
`frozen_points` int(11) DEFAULT '0' COMMENT '冻结积分',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`delete_flag` tinyint(1) DEFAULT '0' COMMENT '是否删除 0 未删除1已删除',
PRIMARY KEY (`account_id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='积分账户表,记录用户的积分信息';
-- 4. 积分流水表
DROP TABLE IF EXISTS `points_transaction`;
CREATE TABLE `points_transaction` (
`transaction_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`user_name` varchar(50) DEFAULT NULL COMMENT '用户名',
`transaction_type` tinyint(1) NOT NULL COMMENT '积分变动类型1.获取积分 2.消费积分 3.过期 4.其他',
`points` int(11) NOT NULL COMMENT '变动积分',
`before_points` int(11) NOT NULL COMMENT '变动前积分',
`after_points` int(11) NOT NULL COMMENT '变动后积分',
`status` tinyint(1) NOT NULL COMMENT '交易状态1.成功 2.失败 3.处理中',
`transaction_no` varchar(50) NOT NULL COMMENT '交易单号',
`pay_type` tinyint(1) DEFAULT NULL COMMENT '支付方式1.微信 2.支付宝 3.余额支付',
`business_id` bigint(20) DEFAULT NULL COMMENT '关联业务ID',
`business_type` varchar(50) DEFAULT NULL COMMENT '业务类型',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
`update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
`delete_flag` tinyint(1) DEFAULT '0' COMMENT '是否删除 0 未删除1已删除',
PRIMARY KEY (`transaction_id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_transaction_no` (`transaction_no`),
KEY `idx_business_id` (`business_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='积分流水表,记录用户的积分变动情况';
-- 5. 内容购买记录表
DROP TABLE IF EXISTS `content_purchase`;
CREATE TABLE `content_purchase` (
`purchase_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`user_name` varchar(50) DEFAULT NULL COMMENT '用户名',
`content_id` bigint(20) NOT NULL COMMENT '内容ID',
`content_title` varchar(255) DEFAULT NULL COMMENT '内容标题',
`pay_type` tinyint(1) NOT NULL COMMENT '购买方式1.余额支付 2.积分支付',
`amount` decimal(10,2) DEFAULT NULL COMMENT '支付金额',
`points` int(11) DEFAULT NULL COMMENT '支付积分',
`status` tinyint(1) NOT NULL COMMENT '购买状态1.待支付 2.已支付 3.已取消',
`purchase_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '购买时间',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`delete_flag` tinyint(1) DEFAULT '0' COMMENT '是否删除 0 未删除1已删除',
PRIMARY KEY (`purchase_id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_content_id` (`content_id`),
KEY `idx_user_content` (`user_id`,`content_id`) COMMENT '联合索引,用于快速查询用户是否已购买某内容'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='内容购买记录表,记录用户购买的内容信息';
-- 6. 支付订单表
DROP TABLE IF EXISTS `payment_order`;
CREATE TABLE `payment_order` (
`order_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`order_no` varchar(50) NOT NULL COMMENT '订单号',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`user_name` varchar(50) DEFAULT NULL COMMENT '用户名',
`amount` decimal(10,2) NOT NULL COMMENT '支付金额',
`pay_type` tinyint(1) NOT NULL COMMENT '支付方式1.微信 2.支付宝',
`status` tinyint(1) NOT NULL COMMENT '支付状态1.待支付 2.已支付 3.支付失败 4.已取消 5.已退款',
`channel_order_no` varchar(50) DEFAULT NULL COMMENT '支付渠道订单号',
`product_name` varchar(255) DEFAULT NULL COMMENT '商品名称',
`product_desc` varchar(255) DEFAULT NULL COMMENT '商品描述',
`business_id` bigint(20) DEFAULT NULL COMMENT '关联业务ID',
`business_type` varchar(50) DEFAULT NULL COMMENT '业务类型',
`notify_url` varchar(255) DEFAULT NULL COMMENT '支付回调地址',
`return_url` varchar(255) DEFAULT NULL COMMENT '支付成功跳转地址',
`expire_time` datetime DEFAULT NULL COMMENT '过期时间',
`pay_time` datetime DEFAULT NULL COMMENT '支付时间',
`remark` varchar(255) DEFAULT NULL COMMENT '支付备注',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`delete_flag` tinyint(1) DEFAULT '0' COMMENT '是否删除 0 未删除1已删除',
PRIMARY KEY (`order_id`),
KEY `idx_order_no` (`order_no`),
KEY `idx_user_id` (`user_id`),
KEY `idx_business_id` (`business_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='支付订单表,记录用户的支付请求和支付结果';
-- 7. 内容表
DROP TABLE IF EXISTS `cms_content`;
CREATE TABLE `cms_content` (
`content_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`title` varchar(255) NOT NULL COMMENT '标题',
`subtitle` varchar(255) DEFAULT NULL COMMENT '副标题',
`content_type` tinyint(1) NOT NULL COMMENT '内容类型1文章2视频3图片',
`category_id` bigint(20) DEFAULT NULL COMMENT '分类ID',
`summary` varchar(500) DEFAULT NULL COMMENT '内容摘要',
`content` longtext DEFAULT NULL COMMENT '内容详情',
`cover_image` varchar(255) DEFAULT NULL COMMENT '封面图片',
`author_id` bigint(20) DEFAULT NULL COMMENT '作者ID',
`author_name` varchar(50) DEFAULT NULL COMMENT '作者名称',
`reviewer_id` bigint(20) DEFAULT NULL COMMENT '审核人ID',
`reviewer_name` varchar(50) DEFAULT NULL COMMENT '审核人名称',
`audit_status` tinyint(1) NOT NULL COMMENT '审核状态1草稿2待审核3审核通过4审核拒绝',
`audit_comment` varchar(255) DEFAULT NULL COMMENT '审核意见',
`publish_status` tinyint(1) NOT NULL COMMENT '发布状态1未发布2已发布3已下架',
`publish_time` datetime DEFAULT NULL COMMENT '发布时间',
`view_count` int(11) DEFAULT '0' COMMENT '阅读量',
`like_count` int(11) DEFAULT '0' COMMENT '点赞量',
`comment_count` int(11) DEFAULT '0' COMMENT '评论量',
`sort` int(11) DEFAULT '0' COMMENT '排序',
`is_paid` tinyint(1) DEFAULT '0' COMMENT '是否付费0免费1付费',
`price` decimal(10,2) DEFAULT NULL COMMENT '付费金额',
`required_points` int(11) DEFAULT NULL COMMENT '所需积分',
`support_points_pay` tinyint(1) DEFAULT '0' COMMENT '是否支持积分支付0不支持1支持',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
`update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
`delete_flag` tinyint(1) DEFAULT '0' COMMENT '是否删除 0 未删除1已删除',
PRIMARY KEY (`content_id`),
KEY `idx_category_id` (`category_id`),
KEY `idx_author_id` (`author_id`),
KEY `idx_audit_status` (`audit_status`),
KEY `idx_publish_status` (`publish_status`),
KEY `idx_publish_time` (`publish_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='内容表,记录各种类型的内容信息';
-- 8. 分类表
DROP TABLE IF EXISTS `cms_category`;
CREATE TABLE `cms_category` (
`category_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`category_name` varchar(50) NOT NULL COMMENT '分类名称',
`parent_id` bigint(20) DEFAULT '0' COMMENT '父分类ID',
`level` int(11) DEFAULT '1' COMMENT '分类层级',
`sort` int(11) DEFAULT '0' COMMENT '排序',
`status` tinyint(1) DEFAULT '1' COMMENT '状态1启用2禁用',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
`update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
`delete_flag` tinyint(1) DEFAULT '0' COMMENT '是否删除 0 未删除1已删除',
PRIMARY KEY (`category_id`),
KEY `idx_parent_id` (`parent_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='分类表,记录内容的分类信息';
-- 9. 标签表
DROP TABLE IF EXISTS `cms_tag`;
CREATE TABLE `cms_tag` (
`tag_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`tag_name` varchar(50) NOT NULL COMMENT '标签名称',
`description` varchar(255) DEFAULT NULL COMMENT '标签描述',
`use_count` int(11) DEFAULT '0' COMMENT '使用次数',
`status` tinyint(1) DEFAULT '1' COMMENT '状态1启用2禁用',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
`update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
`delete_flag` tinyint(1) DEFAULT '0' COMMENT '是否删除 0 未删除1已删除',
PRIMARY KEY (`tag_id`),
UNIQUE KEY `uk_tag_name` (`tag_name`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='标签表,记录内容的标签信息';
-- 10. 系统用户表
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_name` varchar(50) NOT NULL COMMENT '用户登录名称',
`pwd` varchar(100) NOT NULL COMMENT '密码(非明文)',
`real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名',
`tel` varchar(20) DEFAULT NULL COMMENT '手机',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
`salt` varchar(50) DEFAULT NULL COMMENT '加点盐(登录时候要用到的随机数)',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`enable` tinyint(1) DEFAULT '1' COMMENT '是否启用1启用2禁用',
`delete_flag` tinyint(1) DEFAULT '0' COMMENT '是否删除 0 未删除1已删除',
PRIMARY KEY (`user_id`),
UNIQUE KEY `uk_user_name` (`user_name`),
KEY `idx_enable` (`enable`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统用户表,记录系统用户信息';
-- 11. 系统角色表
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`role_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色ID',
`role_code` varchar(50) NOT NULL COMMENT '角色编码',
`role_name` varchar(50) NOT NULL COMMENT '角色名称',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
`delete_flag` varchar(1) DEFAULT '0' COMMENT '删除标记',
PRIMARY KEY (`role_id`),
UNIQUE KEY `uk_role_code` (`role_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统角色表,记录系统角色信息';
-- 12. 系统用户角色关联表
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`role_id` bigint(20) NOT NULL COMMENT '角色ID',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
PRIMARY KEY (`role_id`,`user_id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统用户角色关联表,记录用户与角色的关联关系';
-- 13. 系统菜单表
DROP TABLE IF EXISTS `sys_menu`;
CREATE TABLE `sys_menu` (
`menu_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`menu_pid` bigint(20) DEFAULT NULL COMMENT '为空时表示是子系统',
`menu_name` varchar(50) NOT NULL COMMENT '菜单名称',
`menu_src` varchar(255) DEFAULT NULL COMMENT '菜单链接地址',
`menu_icon` varchar(50) DEFAULT NULL COMMENT '菜单图标',
`menu_style` varchar(50) DEFAULT NULL COMMENT '菜单样式',
`sort` int(11) DEFAULT '0' COMMENT '值越小越排在前面',
`note` varchar(255) DEFAULT NULL COMMENT '备注',
`delete_flag` varchar(1) DEFAULT '0' COMMENT '删除标记',
PRIMARY KEY (`menu_id`),
KEY `idx_menu_pid` (`menu_pid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统菜单表,记录系统菜单信息';
-- 14. 系统字典表
DROP TABLE IF EXISTS `sys_dict`;
CREATE TABLE `sys_dict` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '字典表ID',
`dict_code` varchar(50) NOT NULL COMMENT '字典编码',
`dict_name` varchar(50) NOT NULL COMMENT '字典名称',
`dict_cn` varchar(50) DEFAULT NULL COMMENT '字典值中文文本',
`dict_en` varchar(50) DEFAULT NULL COMMENT '字典值英文文本',
`dict_value` varchar(50) DEFAULT NULL COMMENT '字典值',
`sorts` int(11) DEFAULT NULL COMMENT '字典排序',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_dict_code` (`dict_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统字典表,记录系统字典信息';
-- 15. 系统日志表
DROP TABLE IF EXISTS `sys_log`;
CREATE TABLE `sys_log` (
`log_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`user_id` varchar(50) DEFAULT NULL COMMENT '用户ID',
`user_name` varchar(50) DEFAULT NULL COMMENT '用户名称',
`log_type` varchar(50) DEFAULT NULL COMMENT '日志类型',
`log_content` varchar(500) DEFAULT NULL COMMENT '日志类容',
`server_ip` varchar(20) DEFAULT NULL COMMENT '服务端IP',
`client_ip` varchar(20) DEFAULT NULL COMMENT '客户端IP',
`log_time` varchar(20) DEFAULT NULL COMMENT 'yyyyMMddHHmmss',
`note` varchar(255) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`log_id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_log_type` (`log_type`),
KEY `idx_log_time` (`log_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统日志表,记录系统操作日志';
SET FOREIGN_KEY_CHECKS = 1;

81
db/init_data.sql Normal file
View File

@ -0,0 +1,81 @@
-- 初始化数据脚本
-- 作者: 王志维
-- 创建时间: 2026-01-20
-- 设置字符集
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- 1. 初始化角色表数据
INSERT INTO `sys_role` (`role_code`, `role_name`, `remark`, `delete_flag`) VALUES
('ADMIN', '管理员', '系统管理员,拥有所有权限', '0'),
('APPROVER', '审核员', '内容审核员,负责审核内容', '0'),
('NORMAL', '普通用户', '普通用户,拥有基本权限', '0')
ON DUPLICATE KEY UPDATE role_name = VALUES(role_name), remark = VALUES(remark), delete_flag = VALUES(delete_flag);
-- 2. 初始化用户表数据
-- 密码规则密码与用户名相同使用MD5加密 + salt
-- 密码加密逻辑MD5Util.encryptToHex(plainPassword + salt)
-- 登录验证逻辑MD5Util.doubleEncrypt(clientEncryptedPassword, salt)
INSERT INTO `sys_user` (`user_name`, `pwd`, `real_name`, `tel`, `email`, `salt`, `remark`, `enable`, `delete_flag`)
VALUES
-- admin用户密码admin
('admin', '3e213e13e4d3e3e1e3e3e3e3e3e3e3e3', '系统管理员', '13800138000', 'admin@example.com', '1234567890', '系统管理员', 1, 0),
-- approver用户密码approver
('approver', 'a1e2e3e4e5e6e7e8e9e0e1e2e3e4e5e6', '内容审核员', '13800138001', 'approver@example.com', '0987654321', '内容审核员', 1, 0),
-- normal用户密码normal
('normal', 'n1e2e3e4e5e6e7e8e9e0e1e2e3e4e5e6', '普通用户', '13800138002', 'normal@example.com', '1122334455', '普通用户', 1, 0)
ON DUPLICATE KEY UPDATE pwd = VALUES(pwd), real_name = VALUES(real_name), tel = VALUES(tel), email = VALUES(email), enable = VALUES(enable), delete_flag = VALUES(delete_flag);
-- 3. 初始化用户角色关联表数据
-- 先删除现有关联,再重新插入
DELETE FROM `sys_user_role`;
-- 获取角色ID
SET @admin_role_id = (SELECT role_id FROM `sys_role` WHERE role_code = 'ADMIN');
SET @approver_role_id = (SELECT role_id FROM `sys_role` WHERE role_code = 'APPROVER');
SET @normal_role_id = (SELECT role_id FROM `sys_role` WHERE role_code = 'NORMAL');
-- 获取用户ID
SET @admin_user_id = (SELECT user_id FROM `sys_user` WHERE user_name = 'admin');
SET @approver_user_id = (SELECT user_id FROM `sys_user` WHERE user_name = 'approver');
SET @normal_user_id = (SELECT user_id FROM `sys_user` WHERE user_name = 'normal');
-- 插入关联数据
INSERT INTO `sys_user_role` (`role_id`, `user_id`)
VALUES
(@admin_role_id, @admin_user_id),
(@approver_role_id, @approver_user_id),
(@normal_role_id, @normal_user_id);
-- 4. 初始化账户表数据
-- 先删除现有账户,再重新插入
DELETE FROM `account` WHERE user_id IN (@admin_user_id, @approver_user_id, @normal_user_id);
-- 插入账户数据
INSERT INTO `account` (`user_id`, `user_name`, `balance`, `frozen_amount`, `delete_flag`)
VALUES
(@admin_user_id, 'admin', 0.00, 0.00, 0),
(@approver_user_id, 'approver', 0.00, 0.00, 0),
(@normal_user_id, 'normal', 0.00, 0.00, 0);
-- 5. 初始化积分账户表数据
-- 先删除现有积分账户,再重新插入
DELETE FROM `points_account` WHERE user_id IN (@admin_user_id, @approver_user_id, @normal_user_id);
-- 插入积分账户数据
INSERT INTO `points_account` (`user_id`, `user_name`, `total_points`, `available_points`, `frozen_points`, `delete_flag`)
VALUES
(@admin_user_id, 'admin', 0, 0, 0, 0),
(@approver_user_id, 'approver', 0, 0, 0, 0),
(@normal_user_id, 'normal', 0, 0, 0, 0);
SET FOREIGN_KEY_CHECKS = 1;
-- 输出初始化结果
SELECT '初始化数据完成' AS result;
SELECT '角色表初始化行数:', ROW_COUNT() AS count FROM `sys_role`;
SELECT '用户表初始化行数:', ROW_COUNT() AS count FROM `sys_user`;
SELECT '用户角色关联表初始化行数:', ROW_COUNT() AS count FROM `sys_user_role`;
SELECT '账户表初始化行数:', ROW_COUNT() AS count FROM `account`;
SELECT '积分账户表初始化行数:', ROW_COUNT() AS count FROM `points_account`;

159
mvnw.cmd vendored Normal file
View File

@ -0,0 +1,159 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "on" ("%HOME%\mavenrc_pre.bat" %*)
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo. goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
if not "%MAVEN_PROJECTBASEDIR%" == "" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
if exist "%WDIR%\.mvn" goto baseDirFound
cd ..
if "%WDIR%" == "%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{$client = new-object System.Net.WebClient; $client.DownloadFile(%DOWNLOAD_URL%, %WRAPPER_JAR%);}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* || set ERROR_CODE=1
:end
@REM setlocal
goto mainEnd
:error
set ERROR_CODE=1
:mainEnd
@REM setlocal
@REM Execute a user defined script after this one
if not "%MAVEN_SKIP_RC%" == "on" ("%HOME%\mavenrc_post.bat")
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%

327
pom.xml Normal file
View File

@ -0,0 +1,327 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.kexue</groupId>
<artifactId>skills</artifactId>
<name>agentSkills</name>
<version>0.0.1-SNAPSHOT</version>
<description>可学AI-skills平台</description>
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>3.2.2</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!--Thymeleaf 启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--spring security
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency> -->
<!--commons-lang3 扩展工具包,如文件上传-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
<!-- Maven 解决方案 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version> <!-- 最低需2.5版本包含该类 -->
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Swagger 2 Dependencies -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
<!-- Springdoc OpenAPI (for Swagger 3 compatibility) -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version>
</dependency>
<!-- Swagger Annotations -->
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.2.20</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- Logging Starter (includes Logback) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!-- JAX-RS API for javax annotations -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
<!-- Servlet API for javax.servlet.http -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- Google Guava for cache -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.2</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis.spring</artifactId>
</exclusion>
<exclusion>
<groupId>log4j-slf4j-impl</groupId>
<artifactId>org.apache.logging.log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jul-to-slf4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Sa-Token 核心依赖 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-spring-boot3-starter</artifactId>
<version>1.38.0</version>
</dependency>
<!-- Sa-Token 整合 Redis 使用jackson序列化方式 -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-redis-jackson</artifactId>
<version>1.38.0</version>
</dependency>
<!-- Easy Captcha 验证码库 -->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>1.6.2</version>
</dependency>
<!-- JetCache 核心依赖 -->
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis</artifactId>
<version>2.7.8</version>
</dependency>
<!-- Apache Commons Pool2 连接池库 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.12.0</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>agentSkills</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-J-Xmx1024m</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.kexue.skills.SkillsApp</mainClass>
<skip>false</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<!-- fonts file cannot use filter as the data structure of byte file will be changed via filter -->
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>static/layui/font/**</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
</project>

View File

@ -0,0 +1,27 @@
package com.kexue.skills;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.InetAddress;
import java.net.UnknownHostException;
@SpringBootApplication
@MapperScan(basePackages = "com.kexue.skills.mapper")
@EnableAspectJAutoProxy
@EnableScheduling
public class SkillsApp {
public static void main(String[] args) {
SpringApplication.run(SkillsApp.class, args);
}
}

View File

@ -0,0 +1,25 @@
package com.kexue.skills.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 维哥
* @Description
* @create 2025-03-06 1:15
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Excel {
/**
* 列标题默认取字段名
*/
String label() default "";
/**
* 列排序值越小越靠前
*/
int sort() default 100;
}

View File

@ -0,0 +1,17 @@
package com.kexue.skills.annotation;
/**
* @author 维哥
* @Description 防止重复提交注解
* @create 2025-02-25 15:35
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PreventDuplicateSubmission {
long timeout() default 1000; // 默认超时时间为1秒
}

View File

@ -0,0 +1,16 @@
package com.kexue.skills.annotation;
/**
* @author 维哥
* @Description 登录验证注解
* @create 2025-02-25 15:43
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequireAuth {
}

View File

@ -0,0 +1,21 @@
package com.kexue.skills.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author 维哥
* @Description 角色权限验证注解
* @create 2025-02-25 15:43
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequireRole {
/**
* 角色编码列表
* @return 角色编码列表
*/
String[] value() default {};
}

View File

@ -0,0 +1,77 @@
package com.kexue.skills.aspect;
import com.kexue.skills.annotation.RequireAuth;
import com.kexue.skills.common.ResultCode;
import com.kexue.skills.exception.BizException;
import com.kexue.skills.interceptor.UserContextHolder;
import com.kexue.skills.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import jakarta.servlet.http.HttpServletRequest;
import javax.annotation.Resource;
/**
* @author 维哥
* @Description 登录认证切面
* @create 2025-02-25 15:43
*/
@Aspect
@Component
@Slf4j
public class AuthAspect {
@Resource
private SysUserService sysUserService;
// 处理方法级别注解
@Around("@annotation(com.kexue.skills.annotation.RequireAuth)")
public Object requireAuthMethod(ProceedingJoinPoint joinPoint) throws Throwable {
return requireAuthImpl(joinPoint);
}
// 处理类级别注解
@Around("@within(com.kexue.skills.annotation.RequireAuth)")
public Object requireAuthClass(ProceedingJoinPoint joinPoint) throws Throwable {
return requireAuthImpl(joinPoint);
}
// 实际的认证逻辑
private Object requireAuthImpl(ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("Authorization");
StringBuffer requestURL = request.getRequestURL();
// 获取方法签名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
try {
// 使用Sa-Token检查登录状态
cn.dev33.satoken.stp.StpUtil.checkLogin();
// 获取当前登录用户ID
Object loginId = cn.dev33.satoken.stp.StpUtil.getLoginId();
// 根据用户ID获取用户名
String username = sysUserService.queryById(Long.parseLong(loginId.toString())).getUserName();
log.info("用户名:{}token{}, URL:{}, 方法:{}.{}",
username, token, requestURL.toString(),
signature.getDeclaringType().getSimpleName(),
signature.getMethod().getName());
// 设置用户上下文
UserContextHolder.setUserName(username);
return joinPoint.proceed();
} catch (Exception e) {
log.error("认证失败:{}", e.getMessage());
throw new BizException(ResultCode.TOKEN_FAILED.getCode(), "无效的token请重新登录");
}
}
}

View File

@ -0,0 +1,77 @@
package com.kexue.skills.aspect;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.kexue.skills.annotation.PreventDuplicateSubmission;
import com.kexue.skills.exception.BizException;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import jakarta.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;
/**
* @author 维哥
* @Description
* @create 2025-02-25 15:33
*/
@Aspect
@Component
public class PreventDuplicateSubmissionAspect {
private static final Cache<String, Long> requestCache = CacheBuilder.newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES) // 缓存1分钟
.build();
// 处理方法级别注解
@Around("@annotation(com.kexue.skills.annotation.PreventDuplicateSubmission)")
public Object preventDuplicateSubmissionMethod(ProceedingJoinPoint joinPoint) throws Throwable {
return preventDuplicateSubmissionImpl(joinPoint);
}
// 处理类级别注解
@Around("@within(com.kexue.skills.annotation.PreventDuplicateSubmission)")
public Object preventDuplicateSubmissionClass(ProceedingJoinPoint joinPoint) throws Throwable {
return preventDuplicateSubmissionImpl(joinPoint);
}
// 实际的防重复提交逻辑
private Object preventDuplicateSubmissionImpl(ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String key = generateKey(request, joinPoint.getSignature().toShortString());
// 从joinPoint获取方法签名和注解
org.aspectj.lang.reflect.MethodSignature signature = (org.aspectj.lang.reflect.MethodSignature) joinPoint.getSignature();
// 先从方法上获取注解
PreventDuplicateSubmission preventDuplicateSubmission = signature.getMethod().getAnnotation(PreventDuplicateSubmission.class);
// 如果方法上没有再从类上获取
if (preventDuplicateSubmission == null) {
preventDuplicateSubmission = (PreventDuplicateSubmission)signature.getDeclaringType().getAnnotation(PreventDuplicateSubmission.class);
}
// 确保注解存在
if (preventDuplicateSubmission == null) {
throw new BizException("无法获取PreventDuplicateSubmission注解");
}
Long lastRequestTime = requestCache.getIfPresent(key);
long currentTime = System.currentTimeMillis();
if (lastRequestTime != null && (currentTime - lastRequestTime) < preventDuplicateSubmission.timeout()) {
throw new BizException("瞬间操作过于频繁,请稍后再试");
}
requestCache.put(key, currentTime);
return joinPoint.proceed();
}
private String generateKey(HttpServletRequest request, String methodSignature) {
return request.getSession().getId() + ":" + methodSignature;
}
}

View File

@ -0,0 +1,107 @@
package com.kexue.skills.aspect;
import com.kexue.skills.annotation.RequireRole;
import com.kexue.skills.common.ResultCode;
import com.kexue.skills.exception.BizException;
import com.kexue.skills.interceptor.UserContextHolder;
import com.kexue.skills.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import jakarta.servlet.http.HttpServletRequest;
import javax.annotation.Resource;
/**
* @author 维哥
* @Description 角色权限验证切面
* @create 2025-02-25 15:43
*/
@Aspect
@Component
@Slf4j
public class RoleAspect {
@Resource
private SysUserService sysUserService;
// 处理方法级别注解
@Around("@annotation(com.kexue.skills.annotation.RequireRole)")
public Object requireRoleMethod(ProceedingJoinPoint joinPoint) throws Throwable {
return requireRoleImpl(joinPoint);
}
// 处理类级别注解
@Around("@within(com.kexue.skills.annotation.RequireRole)")
public Object requireRoleClass(ProceedingJoinPoint joinPoint) throws Throwable {
return requireRoleImpl(joinPoint);
}
// 实际的权限验证逻辑
private Object requireRoleImpl(ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("Authorization");
StringBuffer requestURL = request.getRequestURL();
// 从joinPoint获取方法签名和注解
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
// 先从方法上获取注解
RequireRole requireRole = signature.getMethod().getAnnotation(RequireRole.class);
// 如果方法上没有再从类上获取
if (requireRole == null) {
requireRole = (RequireRole)signature.getDeclaringType().getAnnotation(RequireRole.class);
}
// 确保注解存在
if (requireRole == null) {
log.error("无法获取RequireRole注解方法{},类:{}",
signature.getMethod().getName(),
signature.getDeclaringType().getName());
throw new BizException(ResultCode.PERMISSION_DENIED.getCode(), "无法验证权限,缺少注解配置");
}
try {
// 使用Sa-Token检查登录状态
cn.dev33.satoken.stp.StpUtil.checkLogin();
// 获取当前登录用户ID
Object loginId = cn.dev33.satoken.stp.StpUtil.getLoginId();
// 根据用户ID获取用户名
String username = sysUserService.queryById(Long.parseLong(loginId.toString())).getUserName();
log.info("用户名:{}token{}, URL:{}, 需要角色:{}", username, token, requestURL.toString(), String.join(",", requireRole.value()));
log.debug("获取到的RequireRole注解value={}, 注解类型:{}",
String.join(",", requireRole.value()),
requireRole.getClass().getName());
// 获取用户的角色列表
String[] requiredRoles = requireRole.value();
if (requiredRoles != null && requiredRoles.length > 0) {
// 使用Sa-Token检查角色权限
cn.dev33.satoken.stp.StpUtil.checkRoleAnd(requiredRoles);
}
// 设置用户上下文
UserContextHolder.setUserName(username);
return joinPoint.proceed();
} catch (cn.dev33.satoken.exception.NotLoginException e) {
log.error("未登录:{}", e.getMessage());
throw new BizException(ResultCode.TOKEN_FAILED.getCode(), "请先登录认证后操作");
} catch (cn.dev33.satoken.exception.NotRoleException e) {
log.error("权限不足:{}", e.getMessage());
throw new BizException(ResultCode.PERMISSION_DENIED.getCode(), "没有访问权限");
} catch (Exception e) {
log.error("权限验证失败:{}", e.getMessage());
throw new BizException(ResultCode.PERMISSION_DENIED.getCode(), "权限验证失败");
}
}
}

View File

@ -0,0 +1,52 @@
package com.kexue.skills.common;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.concurrent.TimeUnit;
/**
* @author 维哥
* @Description 缓存管理器
* @create 2025-02-25 15:25
*/
public class CacheManager {
// 创建一个缓存实例设置缓存时间为180分钟
private static final Cache<String, String> tokenCache = CacheBuilder.newBuilder()
.expireAfterWrite(3, TimeUnit.HOURS)
.build();
// 静态方法用于将token放入缓存
public static void putTokenToCache(String username, String token) {
tokenCache.put(username, token);
}
// 静态方法用于从缓存中获取token
public static String getTokenFromCache(String username) {
return tokenCache.getIfPresent(username);
}
// 静态方法用于从缓存中移除token
public static void removeTokenFromCache(String username) {
tokenCache.invalidate(username);
}
// 静态方法用于检查token是否有效
public static boolean isTokenValid(String token) {
return tokenCache.asMap().containsValue(token);
}
// 新增静态方法用于从缓存中通过token获取username
public static String getUsernameFromToken(String token) {
for (String key : tokenCache.asMap().keySet()) {
if (token.equals(tokenCache.getIfPresent(key))) {
return key;
}
}
return null;
}
//查看缓存剩余时间
}

View File

@ -0,0 +1,127 @@
package com.kexue.skills.common;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
/**
* 通用返回对象
* @author Administrator
*/
@ApiModel(value = "公共返回结果类")
@Getter
@Setter
@NoArgsConstructor
@ToString
public class CommonResult<T> {
@Schema(description ="返回编码")
private long status;
@Schema(description ="返回信息")
private String message;
@Schema(description ="返回结果")
private T data;
public CommonResult(long status, String message) {
this.status = status;
this.message = message;
}
protected CommonResult(long status, String message, T data) {
this.status = status;
this.message = message;
this.data = data;
}
/**
* 成功返回结果
*
* @param data 获取的数据
*/
public static <T> CommonResult<T> success(T data) {
return new CommonResult<T>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data);
}
/**
* 成功返回结果
*
* @param errorCode 获取的编码
* @param data 获取的数据
* @param message 提示信息
*/
public static <T> CommonResult<T> success(IErrorCode errorCode, String message,T data) {
return new CommonResult<T>(errorCode.getCode(), message, data);
}
/**
* 成功返回结果
*
* @param errorCode 获取的数据
* @param message 提示信息
*/
public static <T> CommonResult<T> success(IErrorCode errorCode, String message ) {
return new CommonResult<T>(errorCode.getCode(), message,null);
}
/**
* 失败返回结果
* @param errorCode 错误码
*/
public static <T> CommonResult<T> failed(IErrorCode errorCode) {
return new CommonResult<T>(errorCode.getCode(), errorCode.getMessage(), null);
}
/**
* 失败返回结果
* @param errorCode 错误码
* @param message 错误信息
*/
public static <T> CommonResult<T> failed(IErrorCode errorCode,String message) {
return new CommonResult<T>(errorCode.getCode(), message, null);
}
/**
* 失败返回结果
* @param message 提示信息
*/
public static <T> CommonResult<T> failed(String message) {
return new CommonResult<T>(ResultCode.FAILED.getCode(), message, null);
}
/**
* 失败返回结果
* @param message 提示信息
*/
public static <T> CommonResult<T> failed(long errorCode,String message) {
return new CommonResult<T>(errorCode, message, null);
}
/**
* 失败返回结果
*/
public static <T> CommonResult<T> failed() {
return failed(ResultCode.FAILED);
}
/**
* 失败返回结果
*
* @param errorCode 获取的编码
* @param data 获取的数据
* @param message 提示信息
*/
public static <T> CommonResult<T> failed(IErrorCode errorCode, String message,T data) {
return new CommonResult<T>(errorCode.getCode(), message, data);
}
public static <T> CommonResult<T> of(IErrorCode errorCode, String message ,T data) {
return new CommonResult<T>(errorCode.getCode(), message, data);
}
}

View File

@ -0,0 +1,35 @@
package com.kexue.skills.common;
import java.util.Arrays;
import java.util.List;
public interface Const {
String FILE_UPLOAD_DIR = "/data/service/hyxp-portal/upload/file/";
String IMG_UPLOAD_DIR = "/data/service/hyxp-portal/upload/images/";
Integer LOGIN_USER_NOT_FOUND_ERROR = 1;
Integer LOGIN_PASSWOR_ERROR = 2;
Integer LOGIN_SUCCESS = 3;
//用户状态
Integer USER_STATUS_NORMAL = 1;
Integer USER_STATUS_DISABLED = 2;
//是否删除
Integer DELETE_FLAG_YES = 1;
Integer DELETE_FLAG_NO = 0;
List<String> ADMIN_USER_LIST = Arrays.asList("admin","administrator","super","root","boss");
Double TONE_TO_LITERS = 1210d;
Integer PURCHASE_TYPE_LAST_MONTH_REMAINING = 0;
Integer PURCHASE_TYPE_CURRENT_MONTH_PURCHASE = 1;
Integer PURCHASE_STATUS_NOT_SELL_OUT = 0;//未卖完
Integer PURCHASE_STATUS_SELL_OUT = 2;//卖完 1采购完成2售卖完成
Integer IS_RECEIVED_YES = 1;
Integer IS_RECEIVED_NO = 0;
Integer PAYMENT_TYPE_SM = 1; //扫码支付
Integer ACCOUNT_STATUS_ACCOUNTED = 1;//已扎帐
Integer ACCOUNT_STATUS_UNACCOUNTED = 2; //未扎帐
}

View File

@ -0,0 +1,33 @@
package com.kexue.skills.common;
/**
* 错误代号和信息
* 主要处理一些错误相关的信息
**/
public enum ErrorStatus {
OK(200, "OK"),
FOUND(302, "Found"),
BAD_REQUEST(400, "Bad Request"),
UNAUTHORIZED(401, "Unauthorized"),
FORBIDDEN(403, "Forbidden"),
NOT_FOUND(404, "Not Found"),
INTERNAL_SERVER_ERROR(500, "Internal Server Error"),
SERVICE_UNAVAILABLE(503, "Service Unavailable");
private final int code;
private final String message;
ErrorStatus(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}

View File

@ -0,0 +1,20 @@
package com.kexue.skills.common;
/**
* 封装API的错误码
* Created by macro on 2019/4/19.
* @author hurun
*/
public interface IErrorCode {
/**
* 返回错误码
* @return 返回错误码
*/
long getCode();
/**
* 返回错误信息
* @return 返回错误信息
*/
String getMessage();
}

View File

@ -0,0 +1,110 @@
package com.kexue.skills.common;
/**
* 请求返回结果
*
**/
public class Result<T> {
private boolean success = true;
private int code = ErrorStatus.OK.getCode();
private String message = "";
private T data;
public static <T> Result<T> newInstance() {
return new Result<T>();
}
public Result() {
}
public Result(T data) {
this.data = data;
}
public Result(ErrorStatus status) {
this.message = status.getMessage();
this.code = status.getCode();
}
public Result(String message) {
this.message = message;
}
public Result(int code, String message) {
this.message = message;
this.code = code;
}
public Result(int code, String message, T data) {
this.message = message;
this.code = code;
this.data = data;
}
public Result<T> status(ErrorStatus status) {
this.message = message;
this.code = code;
return this;
}
public Result<T> ok() {
success = true;
return this;
}
public Result<T> fail() {
success = false;
return this;
}
public Result<T> message(String message) {
this.message = message;
return this;
}
public Result<T> data(T data) {
this.data = data;
return this;
}
public Result<T> code(int code) {
this.code = code;
return this;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}

View File

@ -0,0 +1,114 @@
package com.kexue.skills.common;
/**
* 枚举了一些常用API操作码
*
* @author macro
* @date 2019/4/19
*/
public enum ResultCode implements IErrorCode {
/**
* 返回成功
* */
SUCCESS(1000, "返回成功"),
/**
* 数据处理成功
* */
SJCL_SUCCESS(1001,"数据处理成功"),
/**
* 上传文件成功
* */
WJSC_SUCCESS(1002,"上传文件成功"),
/**
* 数据模板导入成功
* */
MBDR_SUCCESS(1005,"数据模板导入成功"),
/**
* 数据处理失败
* */
SJCL_FAILED(-1001,"数据处理失败"),
/**
* 上传文件失败
* */
WJSC_FAILED(-1002,"上传文件失败"),
/**
* 导出文件成功
* */
DCWJ_FAILED(-1003,"导出文件失败"),
/**
* token验证失败
* */
TOKEN_FAILED(-1004,"登录认证失败或过期"),
/**
* token验证成功
* */
TOKEN_SUCCESS(1004,"token验证成功"),
/**
* 数据模板导入失败
* */
SJDR_FAILED(-1005,"数据模板导入失败"),
/**
* 返回失败
* */
FAILED(-1000, "返回失败"),
/**
* 参数校验错误
* */
VALIDATE_FAILED(-1007, "参数校验错误"),
/**
* 登录失败
* */
LOGIN_FAILED(-1006,"登录失败"),
/**
* 登录成功
* */
LOGIN_SUCCESS(1006,"登录成功"),
/**
* 资源为空
* */
RESOURCES_SUCCESS(1009,"无访问权限"),
/**
* 资源为空
* */
NOT_ALLOWED(-1009,"无使用权限"),
NOT_ORG(-1010,"不存在的机构"),
/**
* 权限不足
* */
PERMISSION_DENIED(-1011,"没有访问权限"),
/**
* 请稍后再试
* */
BLOCK_HANDLER(-9999,"请稍后再试"),
/**
* 异常访问
* */
FALLBACK(-9998,"异常访问"),
/**
* 统一异常返回码
* */
EXCEPTION_HANDLER(-2500,"服务异常,请联系管理员");
private final long code;
private final String message;
private ResultCode(long code, String message) {
this.code = code;
this.message = message;
}
@Override
public long getCode() {
return code;
}
@Override
public String getMessage() {
return message;
}
}

View File

@ -0,0 +1,48 @@
package com.kexue.skills.common;
/**
* 返回结果工具类
*
**/
public class ResultEntity<T> {
public static boolean isOk(Result<?> result){
return null != result && result.getCode() == ErrorStatus.OK.getCode();
}
public static <T> Result<T> ok(){
return new Result<T>(ErrorStatus.OK);
}
public static <T> Result<T> fail(){
return new Result<T>(ErrorStatus.BAD_REQUEST).fail();
}
public static <T> Result<T> ok(T data){
return new Result<T>(ErrorStatus.OK.getCode(), ErrorStatus.OK.getMessage(), data);
}
public static <T> Result<T> status(ErrorStatus status){
return new Result<T>(status.getCode(), status.getMessage()).fail();
}
public static <T> Result<T> fail(ErrorStatus status){
return new Result<T>(status.getCode(), status.getMessage()).fail();
}
public static <T> Result<T> fail(String message){
return fail(ErrorStatus.BAD_REQUEST.getCode(), message, (T)null).fail();
}
public static <T> Result<T> fail(int code, String message){
return new Result<T>(code, message).fail();
}
public static <T> Result<T> fail(int code ,String message, T data){
return new Result<T>(code, message, data).fail();
}
public static <T> Result<T> notfound(){
return new Result<T>(ErrorStatus.NOT_FOUND).fail();
}
}

View File

@ -0,0 +1,75 @@
package com.kexue.skills.common;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;
public class VerifyCode {
public static String drawRandomText(int width, int height, BufferedImage verifyImg) {
Graphics2D graphics = (Graphics2D) verifyImg.getGraphics();
graphics.setColor(Color.WHITE);//设置画笔颜色-验证码背景色
graphics.fillRect(0, 0, width, height);//填充背景
graphics.setFont(new Font("微软雅黑", Font.BOLD, 40));
//数字和字母的组合
String baseNumLetter = "123456789abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
StringBuilder builder = new StringBuilder();
int x = 10; //旋转原点的 x 坐标
String ch;
Random random = new Random();
for (int i = 0; i < 4; i++) {
graphics.setColor(getRandomColor());
//设置字体旋转角度
int degree = random.nextInt() % 30; //角度小于30度
int dot = random.nextInt(baseNumLetter.length());
ch = baseNumLetter.charAt(dot) + "";
builder.append(ch);
//正向旋转
graphics.rotate(degree * Math.PI / 180, x, 45);
graphics.drawString(ch, x, 45);
//反向旋转
graphics.rotate(-degree * Math.PI / 180, x, 45);
x += 48;
}
//画干扰线
for (int i = 0; i < 6; i++) {
// 设置随机颜色
graphics.setColor(getRandomColor());
// 随机画线
graphics.drawLine(random.nextInt(width), random.nextInt(height),
random.nextInt(width), random.nextInt(height));
}
//添加噪点
for (int i = 0; i < 30; i++) {
int x1 = random.nextInt(width);
int y1 = random.nextInt(height);
graphics.setColor(getRandomColor());
graphics.fillRect(x1, y1, 2, 2);
}
return builder.toString();
}
/**
* 随机取色
*/
private static Color getRandomColor() {
Random ran = new Random();
return new Color(ran.nextInt(256),
ran.nextInt(256), ran.nextInt(256));
}
}

View File

@ -0,0 +1,122 @@
package com.kexue.skills.common.util;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
/**
* AES工具类
*
**/
public class AESUtils {
private static String iv = "0123456789ABCDEF";//偏移量字符串必须是16位 当模式是CBC的时候必须设置偏移量
private static String Algorithm = "AES";
private static String AlgorithmProvider = "AES/ECB/PKCS5Padding"; // 算法/模式/补码方式
public static byte[] generatorKey() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(Algorithm);
keyGenerator.init(256);//默认128获得无政策权限后可为192或256
SecretKey secretKey = keyGenerator.generateKey();
return secretKey.getEncoded();
}
public static IvParameterSpec getIv() throws UnsupportedEncodingException {
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes("utf-8"));
System.out.println("偏移量:"+byteToHexString(ivParameterSpec.getIV()));
return ivParameterSpec;
}
public static byte[] encrypt(String src, byte[] key) throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException, InvalidAlgorithmParameterException {
SecretKey secretKey = new SecretKeySpec(key, Algorithm);
//IvParameterSpec ivParameterSpec = getIv();
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] cipherBytes = cipher.doFinal(src.getBytes(Charset.forName("utf-8")));
return cipherBytes;
}
public static byte[] decrypt(String src, byte[] key) throws Exception {
SecretKey secretKey = new SecretKeySpec(key, Algorithm);
//IvParameterSpec ivParameterSpec = getIv();
Cipher cipher = Cipher.getInstance(AlgorithmProvider);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] hexBytes = hexStringToBytes(src);
byte[] plainBytes = cipher.doFinal(hexBytes);
return plainBytes;
}
/**
* 将byte转换为16进制字符串
* @param src
* @return
*/
public static String byteToHexString(byte[] src) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xff;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
sb.append("0");
}
sb.append(hv);
}
return sb.toString();
}
/**
* 将16进制字符串装换为byte数组
* @param hexString
* @return
*/
public static byte[] hexStringToBytes(String hexString) {
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] b = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
b[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return b;
}
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
public static void main(String[] args) {
try {
// byte key[] = generatorKey();
// 密钥必须是16的倍数
byte key[] = "417256a7dada4236".getBytes("utf-8");//hexStringToBytes("0123456789ABCDEF");
String src = "laoxu123";
System.out.println("密钥:"+byteToHexString(key));
System.out.println("原字符串:"+src);
String enc = byteToHexString(encrypt(src, key));
System.out.println("加密:"+enc);
System.out.println("解密:"+new String(decrypt(enc, key), "utf-8"));
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,99 @@
package com.kexue.skills.common.util;
import java.io.*;
/**
* @author laoxu
**/
public class BytesHelper {
private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
public static int toInt(byte[] bytes)
{
int result = 0;
for (int i = 0; (i < 4) && (i < bytes.length); i++) {
result = (result << 8) - -128 + bytes[i];
}
return result;
}
public static Object byteToObject(byte[] bytes) {
Object obj = null;
try {
ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
ObjectInputStream oi = new ObjectInputStream(bi);
obj = oi.readObject();
bi.close();
oi.close();
} catch (Exception e) {
System.out.println("translation" + e.getMessage());
e.printStackTrace();
}
return obj;
}
public static byte[] objectToByte(Object obj) {
byte[] bytes = (byte[])null;
try {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(obj);
bytes = bo.toByteArray();
bo.close();
oo.close();
} catch (Exception e) {
System.out.println("translation" + e.getMessage());
e.printStackTrace();
}
return bytes;
}
public static byte[] inputStreamToByte(InputStream is) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
int ch;
while ((ch = is.read()) != -1)
{
os.write(ch);
}
byte[] bystes = os.toByteArray();
os.close();
return bystes;
}
public static String byteArrayToHexString(byte[] bytes)
{
char[] chars = new char[bytes.length * 2];
int ii = 0;
for (int i = 0; i < bytes.length; i++)
{
byte b = bytes[i];
chars[(ii++)] = HEX_DIGITS[(b >>> 4 & 0xF)];
chars[(ii++)] = HEX_DIGITS[(b & 0xF)];
}
return new String(chars);
}
public static byte[] hexStringToByteArray(String hexString) {
byte[] bytes = new byte[hexString.length() / 2];
int ii = 0;
char[] chars = hexString.toCharArray();
for (int i = 0; i < bytes.length; i++) {
int ch = charToInteger(chars[(ii++)]);
int cl = charToInteger(chars[(ii++)]);
int b = ch << 4 | cl;
bytes[i] = ((byte)b);
}
return bytes;
}
public static int charToInteger(char c) {
if ((c >= '0') && (c <= '9'))
return c - '0';
if ((c >= 'a') && (c <= 'f'))
return '\n' + c - 97;
if ((c >= 'A') && (c <= 'F')) {
return '\n' + c - 65;
}
return 0;
}
}

View File

@ -0,0 +1,90 @@
package com.kexue.skills.common.util;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import java.util.Date;
/**
* @author 维哥
* @Description
* @create 2025-03-03 10:58
*/
public class DateConverter {
/**
* 将中文日期格式转换为标准格式yyyy-MM-dd
* @param chineseDate 示例"2025年2月22日"
* @return 示例"2025-02-22"
*/
public static String convertChineseDate(String chineseDate) {
if (StrUtil.isBlank(chineseDate)) return null;
return DateUtil.parse(chineseDate.replace("", ""), "yyyy年M月d")
.toString("yyyy-MM-dd");
}
/**
* 将简写时间转换为标准时间格式HH:mm:ss
* @param shortTime 示例"1:30" "12:5"
* @return 示例"01:30:00" "12:05:00"
*/
public static String convertShortTime(String shortTime) {
if (StrUtil.isBlank(shortTime)) return null;
// 处理缺失前导零的情况
String[] parts = shortTime.split(":");
if (parts.length != 2) return null;
String hours = String.format("%02d", Integer.parseInt(parts[0]));
String minutes = String.format("%02d", Integer.parseInt(parts[1]));
return DateUtil.parseTime(hours + ":" + minutes + ":00").toString("HH:mm:ss");
}
public static Date convertChineseDateTime(String chineseDate, String shortTime){
Date date = null;
try {
// 清洗非法null字符串
if(chineseDate != null) {
chineseDate.replace(" ","");
chineseDate = chineseDate.replace(" null", ""); // 替换时间部分的null
chineseDate = chineseDate.replace("null", ""); // 处理其他可能的null情况
chineseDate = convertChineseDate(chineseDate);
}
if(shortTime != null) {
shortTime.replace(" ","");
shortTime = shortTime.replace(" null", ""); // 替换时间部分的null
shortTime = shortTime.replace("null", ""); // 处理其他可能的null情况
shortTime = convertShortTime(shortTime);
}
if (StrUtil.isNotBlank(chineseDate) && StrUtil.isNotBlank(shortTime)){
date = DateUtil.parse(chineseDate+ " " + convertShortTime(shortTime)==null?"00:00:00":convertShortTime(shortTime));
}
if (StrUtil.isNotBlank(chineseDate) && StrUtil.isBlank(shortTime)){
return DateUtil.parse(chineseDate);
}
} catch (Exception e) {
e.printStackTrace();//
}
date = DateUtil.parse(chineseDate + " 00:00:00");
return date;
}
public static String convertChineseDateTimeStr(String chineseDate, String shortTime){
if (StrUtil.isNotBlank(chineseDate) || StrUtil.isNotBlank(shortTime)){
return convertChineseDate(chineseDate)+ " " + convertShortTime(shortTime);
}
return "";
}
// 测试示例
public static void main(String[] args) {
System.out.println(convertChineseDate("2025年2月22日")); // 输出2025-02-22
System.out.println(convertShortTime("1:30")); // 输出01:30:00
System.out.println(convertShortTime("12:5")); // 输出12:05:00
}
}

View File

@ -0,0 +1,43 @@
package com.kexue.skills.common.util;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
/**
* @Description: 日期工具类
**/
public class DateUtil {
public static Date getDateAdd(int days){
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
Calendar c = Calendar.getInstance();
c.add(Calendar.DAY_OF_MONTH, -days);
return c.getTime();
}
public static List<String> getDaysBetwwen(int days){
List<String> dayss = new ArrayList<>();
Calendar start = Calendar.getInstance();
start.setTime(getDateAdd(days));
Long startTIme = start.getTimeInMillis();
Calendar end = Calendar.getInstance();
end.setTime(new Date());
Long endTime = end.getTimeInMillis();
Long oneDay = 1000 * 60 * 60 * 24l;
Long time = startTIme;
while (time <= endTime) {
Date d = new Date(time);
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
dayss.add(df.format(d));
time += oneDay;
}
return dayss;
}
/*public static void main(String[] args) {
System.out.println(getDaysBetwwen(7));
}*/
}

View File

@ -0,0 +1,207 @@
package com.kexue.skills.common.util;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import com.kexue.skills.annotation.Excel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.apache.poi.ss.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
// 假设 Excel 注解的定义
public class ExportUtils {
private static final Logger log = LoggerFactory.getLogger(ExportUtils.class);
/**
* 通用Excel导出方法
* @param list 数据集合
* @param clazz 数据类型
* @param outputPath 输出路径含文件名
*/
public static <T> void export(List<T> list, Class<T> clazz, String outputPath) {
if (list == null || clazz == null || StrUtil.isBlank(outputPath)) {
log.error("导出参数异常list、clazz、outputPath 不能为空");
return;
}
// 获取带Excel注解的字段
List<Field> fields;
try {
fields = Arrays.stream(ReflectUtil.getFields(clazz))
.filter(f -> AnnotationUtil.hasAnnotation(f, Excel.class))
.sorted(Comparator.comparingInt(f -> {
Excel excel = AnnotationUtil.getAnnotation(f, Excel.class);
return excel.sort();
}))
.collect(Collectors.toList());
} catch (Exception e) {
log.error("获取带Excel注解的字段时出错", e);
return;
}
// 创建ExcelWriter
try (ExcelWriter writer = ExcelUtil.getWriter()) {
// 设置列标题
fields.forEach(field -> {
Excel excelAnno = AnnotationUtil.getAnnotation(field, Excel.class);
String title = getColumnTitle(field, excelAnno);
writer.addHeaderAlias(field.getName(), title);
});
// 写入数据
writer.write(list, true);
// 输出文件
try {
writer.flush(FileUtil.file(outputPath));
log.info("Excel文件导出成功路径{}", outputPath);
} catch (Exception e) {
log.error("导出Excel文件到路径 {} 时出错", outputPath, e);
}
} catch (Exception e) {
log.error("创建ExcelWriter或写入数据时出错", e);
}
}
/**
* 获取列标题
*/
public static String getColumnTitle(Field field, Excel excelAnno) {
// 优先使用Excel注解的label
if (StrUtil.isNotBlank(excelAnno.label())) {
return excelAnno.label();
}
// 次选ApiModelProperty的value
ApiModelProperty apiModelProperty = AnnotationUtil.getAnnotation(field, ApiModelProperty.class);
if (apiModelProperty != null && StrUtil.isNotBlank(apiModelProperty.value())) {
return apiModelProperty.value();
}
// 最后使用字段名
return field.getName();
}
// 新增流式导出方法
public static <T> void export(List<T> list, Class<T> clazz, OutputStream outputStream) {
try (ExcelWriter writer = ExcelUtil.getWriter()) {
writer.setOnlyAlias(true);
// ============== 新增样式配置 ==============
// 获取样式工具
StyleSet styleSet = writer.getStyleSet();
// 表头样式配置
CellStyle headerStyle = styleSet.getHeadCellStyle();
// 创建表头字体
Font headerFont = writer.createFont();
headerFont.setFontName("微软雅黑"); // 字体
headerFont.setBold(true); // 加粗
headerFont.setFontHeightInPoints((short)12); // 字号
headerFont.setColor(IndexedColors.WHITE.getIndex()); // 字体颜色
// 应用字体到表头样式
headerStyle.setFont(headerFont);
// 设置表头背景色
headerStyle.setFillForegroundColor(IndexedColors.DARK_BLUE.getIndex());
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
// 设置水平居中
headerStyle.setAlignment(HorizontalAlignment.CENTER);
// ============== 样式配置结束 ==============
List<Field> fields = getSortedFields(clazz);
for (Field field : fields) {
Excel excelAnno = AnnotationUtil.getAnnotation(field, Excel.class);
String title = getColumnTitle(field, excelAnno);
System.out.println(title);
writer.addHeaderAlias(field.getName(), title);
}
fields.forEach(field -> {
if (!isSupportedType(field.getType())) {
log.warn("字段 {} 类型 {} 不支持导出,将被忽略", field.getName(), field.getType().getSimpleName());
System.out.println("字段 " + field.getName() + " 类型 " + field.getType().getSimpleName() + " 不支持导出,将被忽略");
}
});
List<Map<String, Object>> dataList = new ArrayList<>();
for (T t : list) {
Map<String, Object> stringObjectMap = BeanUtil.beanToMap(t);
stringObjectMap.forEach((key, value) -> {
if (value == null) {
stringObjectMap.put(key, "");
return;
}
if (value instanceof Date) {
stringObjectMap.put(key, DateUtil.format((Date) value, "yyyy-MM-dd HH:mm:ss"));
} else if (value instanceof Number) { // 包含Integer/Long等
stringObjectMap.put(key, value);
} else if (value instanceof Boolean) {
Boolean boolValue = (Boolean) value; // 显式类型转换
stringObjectMap.put(key, boolValue ? "" : ""); // 布尔值本地化
} else if (value.getClass().isPrimitive()) {
stringObjectMap.put(key, String.valueOf(value));
} else if (!(value instanceof String)) {
// 复杂类型处理按需选择
stringObjectMap.put(key, "");
}
});
dataList.add(stringObjectMap);
}
writer.write(dataList, true);
writer.flush(outputStream);
}
}
// 类型检查方法
private static boolean isSupportedType(Class<?> type) {
return type.isPrimitive()
|| Number.class.isAssignableFrom(type)
|| Date.class.isAssignableFrom(type)
|| String.class == type
|| Boolean.class == type;
}
// 提取公共字段处理逻辑
public static <T> List<Field> getSortedFields(Class<T> clazz) {
return Arrays.stream(ReflectUtil.getFields(clazz))
.filter(f -> AnnotationUtil.hasAnnotation(f, Excel.class))
.sorted(Comparator.comparingInt(f ->
AnnotationUtil.getAnnotation(f, Excel.class).sort()))
.collect(Collectors.toList());
}
// 扩展Web导出方法
public static <T> void webExport(List<T> list, Class<T> clazz, String fileName,
HttpServletResponse response) throws Exception {
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
response.setHeader("Content-Disposition", "attachment;filename=" + encodedFileName);
export(list, clazz, response.getOutputStream()); // 调用新的流式导出方法
}
}

View File

@ -0,0 +1,339 @@
package com.kexue.skills.common.util;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
/**
* @Description: 文件工具类
**/
public final class FileHelper
{
private static final Logger logger = LoggerFactory.getLogger(FileHelper.class);
private FileHelper() {}
/**
* 删除指定位置的文件
* @param path 要删除的文件的完全路径
*/
public static void deleteFile( String path )
{
try
{
File file = new File( path ) ;
file.delete() ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
}
/**
* 在指定位置创建文件
* @param filename 文件路径
*/
public static void createNewFile( String filename )
{
File file = new File( filename ) ;
if( !file.exists() )
{
createNewFileOrDir( file, "f" ) ;
}
}
/**
* 在指定位置创建文件夹
* @param dirname 文件夹路径
*/
public static void createNewDir( String dirname )
{
File file = new File( dirname ) ;
if( file.exists() )
{
createNewFileOrDir( file, "d" ) ;
}
}
/**
* 将字符串写入指定文件使用配置节 "framework.web.charset" 指定的编码集
* @param filename 文件路径
* @param content 写入内容
*/
public static void setContentString( String filename, String content )
{
setContentString( filename, content, "UTF-8" ) ;
}
/**
* 将字符串写入指定文件
* @param filename 文件路径
* @param content 写入内容
* @param charsetName 字符集名称
*/
public static void setContentString( String filename, String content, String charsetName )
{
try
{
setContentBinary(
filename,
content.getBytes( charsetName ) ) ;
}
catch( UnsupportedEncodingException ex )
{
logger.error(ex.getMessage()) ;
}
}
/**
* 将二进制数组写入指定文件
* @param filename 文件路径
* @param arybyte 二进制数组
*/
public static void setContentBinary( String filename, byte[] arybyte )
{
BufferedOutputStream bufferedStream = null ;
try
{
bufferedStream = new BufferedOutputStream( new FileOutputStream( filename ) ) ;
bufferedStream.write( arybyte ) ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
finally
{
try
{
if( bufferedStream != null )
{
bufferedStream.close() ;
}
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
}
}
/**
* 将输入流写入指定文件
* @param filename 文件路径
* @param inputStream 输入流
*/
public static void setContentStream( String filename, InputStream inputStream )
{
try
{
byte[] bytes = IOUtils.toByteArray( inputStream ) ;
setContentBinary( filename, bytes ) ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
finally
{
try
{
if( inputStream != null )
{
inputStream.close() ;
}
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
}
}
/**
* 将字符串添加进指定文件使用配置节 "framework.web.charset" 指定的编码集
* @param filename 文件路径
* @param content 写入内容
*/
public static void appendContentString( String filename, String content )
{
appendContentString( filename, content, "UTF-8" ) ;
}
/**
* 将字符串添加进指定文件
* @param filename 文件路径
* @param content 写入内容
* @param charsetName 字符集名称
*/
public static void appendContentString( String filename, String content, String charsetName )
{
try
{
appendContentBinary(
filename,
content.getBytes( charsetName ) ) ;
}
catch( UnsupportedEncodingException ex )
{
logger.error(ex.getMessage()) ;
}
}
/**
* 将二进制数组添加进指定文件
* @param filename 文件路径
* @param arybyte 要写入的二进制数组
*/
public static void appendContentBinary( String filename, byte[] arybyte )
{
BufferedOutputStream bufferedStream = null ;
try
{
bufferedStream = new BufferedOutputStream( new FileOutputStream( filename, true ) ) ;
bufferedStream.write( arybyte ) ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
finally
{
try
{
if( bufferedStream != null )
{
bufferedStream.close() ;
}
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
}
}
/**
* 将输出流添加进指定文件
* @param filename 文件路径
* @param inputStream 要写入的流
*/
public static void appendContentStream( String filename, InputStream inputStream )
{
try
{
byte[] bytes = IOUtils.toByteArray( inputStream ) ;
appendContentBinary( filename, bytes ) ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
finally
{
try
{
if( inputStream != null )
{
inputStream.close() ;
}
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
}
}
/**
* 创建文件并将指定的字符串写入文件使用配置节 "framework.web.charset" 指定的编码集
* @param path 文件路径
* @param content 写入内容
*/
public static void writeFileString( String path, String content )
{
createNewFile( path ) ;
setContentString( path, content ) ;
}
/**
* 创建文件并将指定的字符串写入文件
* @param path 文件路径
* @param content 写入内容
* @param charsetName 字符集名称
*/
public static void writeFileString( String path, String content, String charsetName )
{
createNewFile( path ) ;
setContentString( path, content, charsetName ) ;
}
/**
* 创建文件并将指定的二进制数组写入文件
* @param path 文件路径
* @param content 要写入的二进制数组
*/
public static void writeFileBinary( String path, byte[] content )
{
createNewFile( path ) ;
setContentBinary( path, content ) ;
}
/**
* 创建文件并将指定的输入流写入文件
* @param path 文件路径
* @param inputStream 要写入的流
*/
public static void writeFileStream( String path, InputStream inputStream )
{
createNewFile( path ) ;
setContentStream( path, inputStream ) ;
}
/**
* 根据文件名获取扩展名
* @param filename 文件名
* @return 扩展名
*/
public static String getExtFromFileName( String filename )
{
int t = filename.lastIndexOf( "\\" ) ;
if( t != -1 )
filename = filename.substring( t + 1 ) ;
t = filename.lastIndexOf( "/" ) ;
if( t != -1 )
filename = filename.substring( t + 1 ) ;
t = filename.lastIndexOf( "." ) ;
if( t != -1 )
return filename.substring( t + 1 ).toLowerCase() ;
return "" ;
}
private static void createNewFileOrDir( File file, String type )
{
try
{
if( type.equals( "d" ) )
file.mkdirs() ;
else
{
file.getParentFile().mkdirs() ;
file.createNewFile() ;
}
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
}
}

View File

@ -0,0 +1,165 @@
package com.kexue.skills.common.util;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import java.lang.reflect.Field;
public class FrontUtils {
public static void main(String[] args) {
// printList(PurchaseDetail.class);
// printEditForm(PurchaseDetail.class);
// printEditMethod(PurchaseDetail.class);
// printInsertMethod(PurchaseDetail.class);
// printFormInitValue(PurchaseDetail.class);
// printList(SaleDetail.class);
// printEditForm(SaleDetail.class);
// printEditMethod(SaleDetail.class);
// printInsertMethod(SaleDetail.class);
// printFormInitValue(SaleDetail.class);
// printList(DailySummaryDto.class);
// printEditForm(DailySummaryDto.class);
// printEditMethod(DailySummaryDto.class);
// printInsertMethod(DailySummaryDto.class);
// printFormInitValue(DailySummaryDto.class);
// printList(SysUser.class);
// printEditForm(SysUser.class);
// printEditMethod(SysUser.class);
// printInsertMethod(SysUser.class);
// printFormInitValue(SysUser.class);
// printList(TradeHistory.class);
// printEditForm(TradeHistory.class);
// printEditMethod(TradeHistory.class);
// printInsertMethod(TradeHistory.class);
// printFormInitValue(TradeHistory.class);
// printList(TradeFactory.class);
// printEditForm(TradeFactory.class);
// printEditMethod(TradeFactory.class);
// printInsertMethod(TradeFactory.class);
// printFormInitValue(TradeFactory.class);
// printList(AccountTransaction.class);
// printEditForm(AccountTransaction.class);
// printEditMethod(AccountTransaction.class);
// printInsertMethod(AccountTransaction.class);
// printFormInitValue(AccountTransaction.class);
// printList(Trade.class);
// printEditForm(Trade.class);
// printEditMethod(Trade.class);
// printInsertMethod(Trade.class);
// printFormInitValue(Trade.class);
// printList(Supplier.class);
// printEditForm(Supplier.class);
// printEditMethod(Supplier.class);
// printInsertMethod(Supplier.class);
// printFormInitValue(Supplier.class);
// printList(ExpenseAccount.class);
// printEditForm(ExpenseAccount.class);
// printEditMethod(ExpenseAccount.class);
// printInsertMethod(ExpenseAccount.class);
// printFormInitValue(ExpenseAccount.class);
// printList(DailyExpenses.class);
// printEditForm(DailyExpenses.class);
// printEditMethod(DailyExpenses.class);
// printInsertMethod(DailyExpenses.class);
// printFormInitValue(DailyExpenses.class);
// printList(BizCardProduct.class);
// printEditForm(BizCardProduct.class);
// printEditMethod(BizCardProduct.class);
// printInsertMethod(BizCardProduct.class);
// printFormInitValue(BizCardProduct.class);
}
public static void printList(Class clazz){
System.out.println("-----------------------printList start-------------------------------------------");
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
if (!declaredField.getName().equals("serialVersionUID")
&& !declaredField.getName().equals("deleteFlag")
){
ApiModelProperty annotation = declaredField.getAnnotation(ApiModelProperty.class);
String label = annotation.value();
if (declaredField.getName().endsWith("Id") || declaredField.getName().equals("id")){
String formHtml = "<el-input v-model=\"editForm."+ declaredField.getName() +"\" v-show=\"false\"></el-input>";
System.out.println(formHtml);
}else {
String formHtml = "<el-table-column sortable prop=\""+ declaredField.getName() +"\" label=\""+ label +"\" width=\"200\"></el-table-column>";
System.out.println(formHtml);
}
}
}
}
public static void printEditForm(Class clazz){
System.out.println("-----------------------printEditForm start-------------------------------------------");
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
if (!declaredField.getName().equals("serialVersionUID")
&& !declaredField.getName().equals("deleteFlag")
){
ApiModelProperty annotation = declaredField.getAnnotation(ApiModelProperty.class);
String label = annotation.value();
if (declaredField.getName().endsWith("Id") || declaredField.getName().equals("id")){
String formHtml = "<el-input v-model=\"editForm."+ declaredField.getName() +"\" v-show=\"false\"></el-input>";
System.out.println(formHtml);
}else {
String formHtml = " <el-form-item label=\""+label+"\" prop=\""+declaredField.getName()+"\">\n" +
" <el-input size=\"small\" v-model=\"editForm."+ declaredField.getName() +"\" auto-complete=\"off\" placeholder=\"请输入"+label+"\"></el-input>\n" +
" </el-form-item>";
System.out.println(formHtml);
}
}
}
}
public static void printEditMethod(Class clazz){
System.out.println("-----------------------printEditMethod start-------------------------------------------");
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
if (!declaredField.getName().equals("serialVersionUID") && !declaredField.getName().equals("deleteFlag")){
ApiModelProperty annotation = declaredField.getAnnotation(ApiModelProperty.class);
String label = annotation.value();
String formHtml = " this.editForm."+ declaredField.getName() +" = row."+ declaredField.getName() +"";
System.out.println(formHtml);
}
}
}
public static void printInsertMethod(Class clazz){
System.out.println("-----------------------printInsertMethod start-------------------------------------------");
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
if (!declaredField.getName().equals("serialVersionUID") && !declaredField.getName().equals("deleteFlag")){
ApiModelProperty annotation = declaredField.getAnnotation(ApiModelProperty.class);
String label = annotation.value();
String formHtml = " this.editForm."+ declaredField.getName() +" = ''";
System.out.println(formHtml);
}
}
}
public static void printFormInitValue(Class clazz){
System.out.println("-----------------------printFormInitValue start-------------------------------------------");
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
if (!declaredField.getName().equals("serialVersionUID") && !declaredField.getName().equals("deleteFlag")){
ApiModelProperty annotation = declaredField.getAnnotation(ApiModelProperty.class);
String label = annotation.value();
String formHtml = ""+ declaredField.getName() +": '',";
System.out.println(formHtml);
}
}
}
}

View File

@ -0,0 +1,23 @@
package com.kexue.skills.common.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.UUID;
/**
* @description: ID管理类
**/
public class IDUtils {
public static final Logger logger = LoggerFactory.getLogger(IDUtils.class);
public static String getUUID(){
return UUID.randomUUID().toString().replace("-","");
}
public static void main(String[] args) {
System.out.println(getUUID());
logger.debug("test");
}
}

View File

@ -0,0 +1,87 @@
package com.kexue.skills.common.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
/**
* 生成图片工具类
*
**/
public class ImageUtil {
private Logger log = LoggerFactory.getLogger(getClass());
private static String DEFAULT_PREVFIX = "thumb_";
private static Boolean DEFAULT_FORCE = false;//建议该值为false
/**
* <p>Title: thumbnailImage</p>
* <p>Description: 根据图片路径生成缩略图 </p>
*
* @param imagePath 原图片路径
* @param w 缩略图宽
* @param h 缩略图高
* @param prevfix 生成缩略图的前缀
* @param force 是否强制按照宽高生成缩略图(如果为false则生成最佳比例缩略图)
*/
public void thumbnailImage(String imagePath, int w, int h, String prevfix, boolean force) {
File imgFile = new File(imagePath);
if (imgFile.exists()) {
try {
// ImageIO 支持的图片类型 : [BMP, bmp, jpg, JPG, wbmp, jpeg, png, PNG, JPEG, WBMP, GIF, gif]
String types = Arrays.toString(ImageIO.getReaderFormatNames());
String suffix = null;
// 获取图片后缀
if (imgFile.getName().indexOf(".") > -1) {
suffix = imgFile.getName().substring(imgFile.getName().lastIndexOf(".") + 1);
}// 类型和图片后缀全部小写然后判断后缀是否合法
if (suffix == null || types.toLowerCase().indexOf(suffix.toLowerCase()) < 0) {
log.error("Sorry, the image suffix is illegal. the standard image suffix is {}." + types);
return;
}
log.debug("target image's size, width:{}, height:{}.", w, h);
Image img = ImageIO.read(imgFile);
if (!force) {
// 根据原图与要求的缩略图比例找到最合适的缩略图比例
int width = img.getWidth(null);
int height = img.getHeight(null);
if ((width * 1.0) / w < (height * 1.0) / h) {
if (width > w) {
h = Integer.parseInt(new java.text.DecimalFormat("0").format(height * w / (width * 1.0)));
log.debug("change image's height, width:{}, height:{}.", w, h);
}
} else {
if (height > h) {
w = Integer.parseInt(new java.text.DecimalFormat("0").format(width * h / (height * 1.0)));
log.debug("change image's width, width:{}, height:{}.", w, h);
}
}
}
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics g = bi.getGraphics();
g.drawImage(img, 0, 0, w, h, Color.LIGHT_GRAY, null);
g.dispose();
String p = imgFile.getPath();
// 将图片保存在原目录并加上前缀
ImageIO.write(bi, suffix, new File(p.substring(0, p.lastIndexOf(File.separator)) + File.separator + prevfix + imgFile.getName()));
log.debug("缩略图在原路径下生成成功");
} catch (IOException e) {
log.error("generate thumbnail image failed.", e);
}
} else {
log.warn("the image is not exist.");
}
}
public static void main(String[] args) {
ImageUtil imageUtil = new ImageUtil();
imageUtil.thumbnailImage("C:\\Users\\ACER\\Pictures\\雷克萨斯\\index-kv-nx-0821-2880x1480.jpg",190,180,DEFAULT_PREVFIX,false);
}
}

View File

@ -0,0 +1,139 @@
package com.kexue.skills.common.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import jakarta.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author laoxu
**/
@Slf4j
public class IpUtil {
public final static String ERROR_IP = "127.0.0.1";
public final static Pattern pattern = Pattern.
compile("(2[5][0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})\\.(25[0-5]|2[0-4]\\d|1\\d{2}|\\d{1,2})");
/**
* 取外网IP
*
* @param request
* @return
*/
public static String getRemoteIp(HttpServletRequest request) {
String ip = request.getHeader("x-real-ip");
if (ip == null) {
ip = request.getRemoteAddr();
}
//过滤反向代理的ip
String[] stemps = ip.split(",");
if (stemps != null && stemps.length >= 1) {
//得到第一个IP即客户端真实IP
ip = stemps[0];
}
ip = ip.trim();
if (ip.length() > 23) {
ip = ip.substring(0, 23);
}
return ip;
}
/**
* 获取用户的真实ip
*
* @param request
* @return
*/
public static String getUserIP(HttpServletRequest request) {
// 优先取X-Real-IP
String ip = request.getHeader("X-Real-IP");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("x-forwarded-for");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
if ("0:0:0:0:0:0:0:1".equals(ip)) {
ip = ERROR_IP;
}
}
if ("unknown".equalsIgnoreCase(ip)) {
ip = ERROR_IP;
return ip;
}
int pos = ip.indexOf(',');
if (pos >= 0) {
ip = ip.substring(0, pos);
}
return ip;
}
public static String getLastIpSegment(HttpServletRequest request) {
String ip = getUserIP(request);
if (ip != null) {
ip = ip.substring(ip.lastIndexOf('.') + 1);
} else {
ip = "0";
}
return ip;
}
public static boolean isValidIP(HttpServletRequest request) {
String ip = getUserIP(request);
return isValidIP(ip);
}
/**
* 判断我们获取的ip是否是一个符合规则ip
*
* @param ip
* @return
*/
public static boolean isValidIP(String ip) {
if (StringUtils.isEmpty(ip)) {
log.debug("ip is null. valid result is false");
return false;
}
Matcher matcher = pattern.matcher(ip);
boolean isValid = matcher.matches();
log.debug("valid ip:" + ip + " result is: " + isValid);
return isValid;
}
public static String getLastServerIpSegment() {
String ip = getServerIP();
if (ip != null) {
ip = ip.substring(ip.lastIndexOf('.') + 1);
} else {
ip = "0";
}
return ip;
}
public static String getServerIP() {
InetAddress inet;
try {
inet = InetAddress.getLocalHost();
String hostAddress = inet.getHostAddress();
return hostAddress;
} catch (UnknownHostException e) {
e.printStackTrace();
}
return "127.0.0.1";
}
}

View File

@ -0,0 +1,43 @@
package com.kexue.skills.common.util;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* md5工具类
*/
public class MD5Util {
public static final int time = 5;
public static final String SALT = "springsecurity";
/**
* 密码加密方法
*
* @param password
* @return
*/
public static String encode(String password) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK).");
}
try {
for (int i = 0; i < time; i++) {
byte[] bytes = digest.digest((password + SALT).getBytes("UTF-8"));
password = String.format("%032x", new BigInteger(1, bytes));
}
return password;
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).");
}
}
public static void main(String[] args) {
System.out.println(MD5Util.encode("admin"));
}
}

View File

@ -0,0 +1,19 @@
//package com.kexue.skills.publisher.common.util;
//
//import org.springframework.security.authentication.AnonymousAuthenticationToken;
//import org.springframework.security.core.Authentication;
//import org.springframework.security.core.context.SecurityContextHolder;
//
///**
// * @Description: spring security工具类
// **/
//public class SecurityUtil {
// public static String getLoginUser(){
// Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// if (!(authentication instanceof AnonymousAuthenticationToken)) {
// String currentUserName = authentication.getName();
// return currentUserName;
// }
// return "";
// }
//}

View File

@ -0,0 +1,247 @@
package com.kexue.skills.common.util;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.FileSystemResource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;
/**
* <p> web 容器中进行上传/下载的静态工具类</p>
* <p>不可继承不可实例化</p>
*/
public final class UploadHelper
{
private static final Logger logger = LoggerFactory.getLogger(UploadHelper.class);
private UploadHelper() {}
private final static String REFERENCE_FILE = "framework-config.xml" ;
/**
* 应用程序的根目录物理路径
*/
public static String BASE_PATH = null ;
/* static
{
try
{
PathMatchingResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver ( Thread.currentThread().getContextClassLoader() ) ;
org.springframework.core.io.Resource resource = resourceResolver.getResource( REFERENCE_FILE ) ;
BASE_PATH = resource.getFile().getParentFile().getParentFile().getParentFile().getPath() + "\\" ;
}
catch( Exception ex )
{
logger.error(ex.getMessage());
}
}*/
/**
* 取得请求的服务器根地址(没有虚拟路径)格式为 "http://主机名:端口"
* @param request 请求实例
* @return 请求的服务器根地址
*/
public static String getRequestServerUrl( HttpServletRequest request )
{
return new StringBuffer( "http://" )
.append( request.getServerName() )
.append( ":" )
.append( request.getServerPort() )
.toString() ;
}
/**
* 为下载页面提供指定位置的文件流内容
* @param response 下载页面的响应实例
* @param filePath 要下载的文件路径
* @param downloadName 下载提示显示的文件名称
* @param mimeType mime类型
*/
public static void sendFile(HttpServletResponse response, String filePath, String downloadName, String disposition, String mimeType )
{
InputStream inStream = null ;
OutputStream outStream = null ;
try
{
/*filePath="D:\\WorkingSoftware\\apache-tomcat-7.0.59\\webapps\\ZZ_OA\\upload\\2015\\9\\111.doc";*/
String fileName =URLEncoder.encode( downloadName , "UTF-8");
response.reset() ;
response.setHeader( "Content-disposition", disposition+"; filename=" + fileName ) ;
response.setContentType( mimeType ) ;
FileSystemResource resource = new FileSystemResource( filePath ) ;
inStream = resource.getInputStream() ;
outStream = response.getOutputStream() ;
byte[] ba = IOUtils.toByteArray( inStream ) ;
outStream.write( ba ) ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
finally
{
try
{
if( inStream != null )
inStream.close() ;
if( outStream != null )
outStream.close() ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
}
}
/**
* 提供重定向文本
* @param response 响应实例
* @param context 文本内容
*/
public static void redirectText(HttpServletResponse response, String context )
{
PrintWriter writer = null ;
try
{
writer = response.getWriter() ;
writer.write( context ) ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
finally
{
try
{
if( writer != null )
writer.close() ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
}
}
/**
* 为下载页面提供字符串内容如果textxml等文档
* @param response 下载页面的响应实例
* @param context 文本内容
* @param downloadName 下载提示显示的文件名称
* @param mimeType mime类型
*/
public static void sendText(HttpServletResponse response, String context, String downloadName, String mimeType )
{
PrintWriter writer = null ;
try
{
String fileName = new String( downloadName.getBytes(), "iso-8859-1" ) ;
response.reset() ;
response.setHeader( "Content-disposition", "attachment; filename=" + fileName ) ;
response.setContentType( mimeType ) ;
writer = response.getWriter() ;
writer.write( context ) ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
finally
{
try
{
if( writer != null )
writer.close() ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
}
}
/**
* 为下载页面提供二进制内容如果wordpdfexecl和zip等文档
* @param response 下载页面的响应实例
* @param binary 二进制内容
* @param downloadName 下载提示显示的文件名称
* @param mimeType mime类型
*/
public static void sendBinary(HttpServletResponse response, byte[] binary, String downloadName, String mimeType )
{
OutputStream outStream = null ;
try
{
String fileName = new String( downloadName.getBytes(), "iso-8859-1" ) ;
response.reset() ;
response.setHeader( "Content-disposition", "attachment; filename=" + fileName ) ;
response.setContentType( mimeType ) ;
outStream = response.getOutputStream() ;
outStream.write( binary ) ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
finally
{
try
{
if( outStream != null )
outStream.close() ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
}
}
/**
* 提供重定向文本
* @param response 响应实例
* @param binary 文本内容
*/
public static void redirectBinary(HttpServletResponse response, byte[] binary )
{
OutputStream writer = null ;
try
{
writer = response.getOutputStream() ;
writer.write( binary ) ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
finally
{
try
{
if( writer != null )
writer.close() ;
}
catch( Exception ex )
{
logger.error(ex.getMessage()) ;
}
}
}
}

View File

@ -0,0 +1,24 @@
package com.kexue.skills.common.util;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.util.UUID;
/**
* @Description: 上传文件工具类
**/
public class UploadUtils {
public static String upload(MultipartFile file, String path, String fileName) throws Exception {
// 生成新的文件名
String realPath = path + "/" + UUID.randomUUID().toString().replace("-", "") + fileName.substring(fileName.lastIndexOf("."));
File dest = new File(realPath);
// 判断文件父目录是否存在
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdir();
}
// 保存文件
file.transferTo(dest);
return dest.getName();
}
}

View File

@ -0,0 +1,30 @@
package com.kexue.skills.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 验证码配置类
* 用于读取application.yml中的验证码配置
*/
@Data
@Component
@ConfigurationProperties(prefix = "captcha")
public class CaptchaConfig {
/**
* 是否启用验证码验证
*/
private boolean enabled = true;
/**
* 验证码有效期
*/
private int expireTime = 300;
/**
* 验证码长度
*/
private int length = 4;
}

View File

@ -0,0 +1,16 @@
package com.kexue.skills.config;
import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation;
import com.alicp.jetcache.anno.config.EnableMethodCache;
import org.springframework.context.annotation.Configuration;
/**
* JetCache配置类
* @author
*/
@Configuration
@EnableCreateCacheAnnotation
@EnableMethodCache(basePackages = "com.kexue.skills.service")
public class JetCacheConfig {
}

View File

@ -0,0 +1,45 @@
package com.kexue.skills.config;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Sa-Token配置类
* @author
*/
@Configuration
public class SaTokenConfig implements WebMvcConfigurer {
/**
* 注册Sa-Token拦截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加Sa-Token拦截器校验规则为StpUtil.checkLogin()
registry.addInterceptor(new SaInterceptor(handler -> {
// 拦截所有请求除了登录注册文档等不需要认证的接口
SaRouter
// 放行登录接口
.match("/login/**").stop()
// 放行注册接口
.match("/register/**").stop()
// 放行Swagger文档
.match("/doc.html").stop()
.match("/swagger-ui/**").stop()
.match("/v3/api-docs/**").stop()
// 放行静态资源
.match("/static/**").stop()
.match("/**/*.css").stop()
.match("/**/*.js").stop()
.match("/**/*.png").stop()
.match("/**/*.jpg").stop()
.match("/**/*.jpeg").stop()
// 其他请求需要登录
.check(() -> StpUtil.checkLogin());
})).addPathPatterns("/**");
}
}

View File

@ -0,0 +1,61 @@
package com.kexue.skills.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
@Component
public class StartupListener implements ApplicationListener<ApplicationReadyEvent> {
private static final Logger logger = LoggerFactory.getLogger(StartupListener.class);
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
String serverPort = event.getApplicationContext().getEnvironment().getProperty("server.port", "8080");
String serverIp = getServerIp();
String localhostUrl = "http://localhost:" + serverPort + "/doc.html";
String ipUrl = "http://" + serverIp + ":" + serverPort + "/doc.html";
logger.info("========================================");
logger.info("API Documentation Access URL:");
logger.info("========================================");
logger.info(" Local: {}", localhostUrl);
logger.info(" Network:{}", ipUrl);
logger.info("========================================\n");
}
/**
* 获取服务器的实际IP地址
* @return 服务器IP地址
*/
private String getServerIp() {
try {
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
while (networkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = networkInterfaces.nextElement();
if (networkInterface.isLoopback() || networkInterface.isVirtual() || !networkInterface.isUp()) {
continue;
}
Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
while (inetAddresses.hasMoreElements()) {
InetAddress inetAddress = inetAddresses.nextElement();
if (inetAddress.isSiteLocalAddress() && !inetAddress.isLoopbackAddress()) {
return inetAddress.getHostAddress();
}
}
}
} catch (SocketException e) {
logger.error("Failed to get server IP address", e);
}
return "127.0.0.1";
}
}

View File

@ -0,0 +1,30 @@
package com.kexue.skills.config;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.License;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@OpenAPIDefinition(
info = @Info(
title = "可学AI-skills平台API",
version = "1.0.0",
description = "API Documentation for Spring MVC Project"
)
)
public class SwaggerConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new io.swagger.v3.oas.models.info.Info()
.title("可学AI-skills平台API")
.version("1.0.0")
.description("API Documentation for Spring MVC Project")
.license(new License().name("Apache 2.0").url("http://springdoc.org")));
}
}

View File

@ -0,0 +1,20 @@
package com.kexue.skills.config;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafProperties;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.templatemode.TemplateMode;
@Configuration(
proxyBeanMethods = false
)
@EnableConfigurationProperties({ThymeleafProperties.class})
@ConditionalOnClass({TemplateMode.class, SpringTemplateEngine.class})
@AutoConfigureAfter({WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class})
public class ThymeleafAutoConfiguration {
}

View File

@ -0,0 +1,21 @@
package com.kexue.skills.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.nio.charset.Charset;
@Component
@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {
private static final Charset DEFAULT_ENCODING = null;
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";
private boolean checkTemplate = true;
private boolean checkTemplateLocation = true;
private String prefix = "classpath:/templates/";
private String suffix = ".html";
private String mode = "HTML";
private Charset encoding;
private boolean cache;
}

View File

@ -0,0 +1,62 @@
package com.kexue.skills.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/** mvc配置例如资源映射视图解析拦截器等
*
**/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
// @Autowired
// SessionTimeoutInterceptor sessionTimeoutInterceptor;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
registry.addResourceHandler("/assets/ckeditor/**").
addResourceLocations("classpath:/static/assets/ckeditor/").
setCachePeriod(2592000);
registry.addResourceHandler("/upload/**").addResourceLocations("file:E://01code//bizcard//upload");
// 配置Swagger UI资源映射
registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/admin").setViewName("admin");
// /doc.html 重定向到 /swagger-ui/index.html
registry.addRedirectViewController("/doc.html", "/swagger-ui/index.html");
/*
registry.addViewController("/index").setViewName("index");
registry.addViewController("/addNew").setViewName("addNew");
registry.addViewController("/myArticle").setViewName("myArticle");
registry.addViewController("/myInformation").setViewName("myInformation");
registry.addViewController("/register").setViewName("register");
registry.addViewController("/submitJournalContegory").setViewName("submitJournalContegory");
registry.addViewController("/submitJournalJournalPrevious").setViewName("submitJournalContegory");
registry.addViewController("/submitJournalJournal").setViewName("submitJournalJournal");
registry.addViewController("/submitJournalUpload").setViewName("submitJournalUpload");*/
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(sessionTimeoutInterceptor).addPathPatterns("/**").
// excludePathPatterns("/toRegister","/getVerifyCode", "/api/**","/index","/doLogin","/login","/register", "/addNew", "/static/**","/logout","/upload/");
}
}

View File

@ -0,0 +1,85 @@
package com.kexue.skills.controller;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.annotation.RequireAuth;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.Account;
import com.kexue.skills.entity.dto.AccountDto;
import com.kexue.skills.service.AccountService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* (Account)表控制层
* 账户管理控制器
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Tag(name = "账户管理 api")
@RestController
@RequestMapping("/api/account")
public class AccountController {
/**
* 服务对象
*/
@Resource
private AccountService accountService;
/**
* 分页查询
*
* @param queryDto 查询参数
* @return 分页结果
*/
@Operation(summary = "分页查询账户", description = "分页查询账户")
@PostMapping("/pageList")
@RequireAuth
public CommonResult<PageInfo<Account>> getPageList(@RequestBody AccountDto queryDto) {
return CommonResult.success(this.accountService.getPageList(queryDto));
}
/**
* 查询列表
*
* @param queryDto 查询参数
* @return 列表结果
*/
@Operation(summary = "查询账户列表", description = "查询账户列表")
@PostMapping("/list")
@RequireAuth
public CommonResult<List<Account>> getList(@RequestBody AccountDto queryDto) {
return CommonResult.success(this.accountService.getList(queryDto));
}
/**
* 通过主键查询单条数据
*
* @param accountId 主键
* @return 单条数据
*/
@Operation(summary = "通过ID查询账户", description = "通过ID查询账户")
@PostMapping("/queryById/{accountId}")
@RequireAuth
public CommonResult<Account> queryById(@Parameter(description = "账户ID") @PathVariable("accountId") Long accountId) {
return CommonResult.success(this.accountService.queryById(accountId));
}
/**
* 通过用户ID查询单条数据
*
* @param userId 用户ID
* @return 单条数据
*/
@Operation(summary = "通过用户ID查询账户", description = "通过用户ID查询账户")
@PostMapping("/queryByUserId/{userId}")
@RequireAuth
public CommonResult<Account> queryByUserId(@Parameter(description = "用户ID") @PathVariable("userId") Long userId) {
return CommonResult.success(this.accountService.queryByUserId(userId));
}
}

View File

@ -0,0 +1,107 @@
package com.kexue.skills.controller;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.common.util.IDUtils;
import com.kexue.skills.config.CaptchaConfig;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* 验证码控制器
* @author
*/
@RestController
@RequestMapping("/api/captcha")
@CrossOrigin(origins = "*")
@Tag(name = "验证码 Api")
public class CaptchaController {
@Resource
private RedisTemplate<String, String> redisTemplate;
@Resource
private CaptchaConfig captchaConfig;
/**
* 生成验证码
* @param response
* @throws IOException
*/
@GetMapping("/generate")
@Operation(summary = "生成验证码", description = "生成验证码")
public CommonResult<Map<String, String>> generateCaptcha() {
// 验证码开关逻辑只有启用时才生成验证码
if (!captchaConfig.isEnabled()) {
return CommonResult.success(new HashMap<>());
}
// 生成验证码ID
String captchaId = IDUtils.getUUID();
// 生成验证码
SpecCaptcha captcha = new SpecCaptcha(130, 48);
// 设置验证码类型为混合类型数字+字母
captcha.setCharType(Captcha.TYPE_DEFAULT);
// 设置验证码长度
captcha.setLen(captchaConfig.getLength());
// 生成验证码文字
String captchaText = captcha.text().toLowerCase();
// 将验证码存储到Redis中使用配置的有效期
redisTemplate.opsForValue().set("captcha:" + captchaId, captchaText, captchaConfig.getExpireTime(), TimeUnit.SECONDS);
// 生成验证码图片的Base64编码
String base64Image = captcha.toBase64();
// 构建返回结果
Map<String, String> result = new HashMap<>();
result.put("captchaId", captchaId);
result.put("captchaImage", base64Image);
return CommonResult.success(result);
}
/**
* 验证验证码
* @param captchaId 验证码ID
* @param captchaValue 用户输入的验证码
* @return
*/
@PostMapping("/verify")
@Operation(summary = "验证验证码", description = "验证验证码")
public CommonResult<Boolean> verifyCaptcha(@RequestParam String captchaId, @RequestParam String captchaValue) {
// 验证码开关逻辑只有启用时才验证验证码
if (!captchaConfig.isEnabled()) {
return CommonResult.success(true);
}
if (captchaId == null || captchaValue == null) {
return CommonResult.failed("验证码ID和验证码值不能为空");
}
// 从Redis中获取验证码
String captchaText = redisTemplate.opsForValue().get("captcha:" + captchaId);
if (captchaText == null) {
return CommonResult.failed("验证码已过期");
}
// 验证验证码
if (captchaText.equals(captchaValue.toLowerCase())) {
// 验证成功后删除验证码
redisTemplate.delete("captcha:" + captchaId);
return CommonResult.success(true);
} else {
return CommonResult.failed("验证码错误");
}
}
}

View File

@ -0,0 +1,129 @@
package com.kexue.skills.controller;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.annotation.RequireAuth;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.CmsCategory;
import com.kexue.skills.entity.base.IdDto;
import com.kexue.skills.entity.dto.CmsCategoryDto;
import com.kexue.skills.service.CmsCategoryService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* (CmsCategory)表控制层
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@RestController
@RequestMapping("api/cmsCategory")
@Tag(name = "内容类目skills-分类) Api")
@CrossOrigin(origins = "*")
public class CmsCategoryController {
/**
* 服务对象
*/
@Resource
private CmsCategoryService cmsCategoryService;
/**
* 分页查询
*
* @param queryDto 筛选条件
* @return 查询结果
*/
@PostMapping("/getPageList")
@Operation(summary = "查询分页列表", description = "查询分页列表")
public CommonResult<PageInfo<CmsCategory>> getPageList(@RequestBody CmsCategoryDto queryDto) {
return CommonResult.success(cmsCategoryService.getPageList(queryDto));
}
/**
* 查询列表
*
* @param queryDto 筛选条件
* @return 查询结果
*/
@PostMapping("/getList")
@Operation(summary = "查询列表", description = "查询列表")
public CommonResult<PageInfo<CmsCategory>> getList(@RequestBody CmsCategoryDto queryDto) {
return CommonResult.success(new PageInfo<>(cmsCategoryService.getList(queryDto)));
}
/**
* 新增数据
*
* @param cmsCategory 实体
* @return 新增结果
*/
@PostMapping("/insert")
@Operation(summary = "新增分类", description = "新增分类")
@RequireAuth
public CommonResult<CmsCategory> insert(@RequestBody CmsCategory cmsCategory) {
return CommonResult.success(cmsCategoryService.insert(cmsCategory));
}
/**
* 编辑数据
*
* @param cmsCategory 实体
* @return 编辑结果
*/
@PostMapping("/update")
@Operation(summary = "更新分类", description = "更新分类")
@RequireAuth
public CommonResult<CmsCategory> update(@RequestBody CmsCategory cmsCategory) {
return CommonResult.success(cmsCategoryService.update(cmsCategory));
}
/**
* 通过主键逻辑删除
*
* @param idDto 主键
* @return 删除数据
*/
@PostMapping("/logicDeleteById")
@Operation(summary = "逻辑删除分类", description = "逻辑删除分类")
@RequireAuth
public CommonResult<Boolean> logicDeleteById(@RequestBody IdDto idDto) {
return CommonResult.success(cmsCategoryService.logicDeleteById(idDto.getId(), "admin") > 0);
}
/**
* 删除数据
*
* @param categoryId 主键
* @return 删除数据
*/
@PostMapping("deleteById/{categoryId}")
@Operation(summary = "物理删除分类", description = "物理删除分类")
@RequireAuth
public CommonResult<Boolean> deleteById(@PathVariable("categoryId") Long categoryId) {
return CommonResult.success(cmsCategoryService.deleteById(categoryId) > 0);
}
/**
* 获取分类树列表
*
* @return 分类树列表
*/
@GetMapping("/getCategoryTreeList")
@Operation(summary = "获取分类树列表", description = "获取分类树列表包含分类名称、分类ID和子分类列表")
public CommonResult<java.util.List<CmsCategory>> getCategoryTreeList() {
return CommonResult.success(cmsCategoryService.getCategoryTreeList());
}
/**
* 获取分类字典
*
* @return 分类字典key为分类IDvalue为分类名称
*/
@GetMapping("/getCategoryDict")
@Operation(summary = "获取分类字典", description = "获取分类字典返回Map<Integer,String>分类ID和分类名称的映射")
public CommonResult<java.util.Map<Long, String>> getCategoryDict() {
return CommonResult.success(cmsCategoryService.getCategoryDict());
}
}

View File

@ -0,0 +1,173 @@
package com.kexue.skills.controller;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.annotation.RequireAuth;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.CmsContent;
import com.kexue.skills.entity.base.IdDto;
import com.kexue.skills.entity.dto.CmsContentDto;
import com.kexue.skills.service.CmsContentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* (CmsContent)表控制层
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@RestController
@RequestMapping("api/cmsContent")
@Tag(name = "内容skills管理 Api")
@CrossOrigin(origins = "*")
public class CmsContentController {
/**
* 服务对象
*/
@Resource
private CmsContentService cmsContentService;
/**
* 分页查询
*
* @param queryDto 筛选条件
* @return 查询结果
*/
@PostMapping("/getPageList")
@Operation(summary = "查询分页列表", description = "查询分页列表")
public CommonResult<PageInfo<CmsContent>> getPageList(@RequestBody CmsContentDto queryDto) {
return CommonResult.success(cmsContentService.getPageList(queryDto));
}
/**
* 查询列表
*
* @param queryDto 筛选条件
* @return 查询结果
*/
@PostMapping("/getList")
@Operation(summary = "查询列表", description = "查询列表")
public CommonResult<PageInfo<CmsContent>> getList(@RequestBody CmsContentDto queryDto) {
return CommonResult.success(new PageInfo<>(cmsContentService.getList(queryDto)));
}
/**
* 通过主键查询单条数据
*
* @param contentId 主键
* @return 单条数据
*/
@PostMapping("queryById/{contentId}")
@Operation(summary = "通过ID查询内容", description = "通过ID查询内容")
public CommonResult<CmsContent> queryById(@PathVariable("contentId") Long contentId) {
// 增加阅读量
cmsContentService.increaseViewCount(contentId);
return CommonResult.success(cmsContentService.queryById(contentId));
}
/**
* 新增数据
*
* @param cmsContent 实体
* @return 新增结果
*/
@PostMapping("/insert")
@Operation(summary = "新增内容", description = "新增内容")
@RequireAuth
public CommonResult<CmsContent> insert(@RequestBody CmsContent cmsContent) {
return CommonResult.success(cmsContentService.insert(cmsContent));
}
/**
* 编辑数据
*
* @param cmsContent 实体
* @return 编辑结果
*/
@PostMapping("/update")
@Operation(summary = "更新内容", description = "更新内容")
@RequireAuth
public CommonResult<CmsContent> update(@RequestBody CmsContent cmsContent) {
return CommonResult.success(cmsContentService.update(cmsContent));
}
/**
* 更新审核状态
*
* @param contentId 内容ID
* @param auditStatus 审核状态
* @param reviewerId 审核人ID
* @param reviewerName 审核人名称
* @param auditComment 审核意见
* @return 审核结果
*/
@PostMapping("/updateAuditStatus")
@Operation(summary = "更新审核状态", description = "更新审核状态")
@RequireAuth
public CommonResult<Boolean> updateAuditStatus(@RequestParam Long contentId,
@RequestParam Integer auditStatus,
@RequestParam Long reviewerId,
@RequestParam String reviewerName,
@RequestParam(required = false) String auditComment) {
return CommonResult.success(cmsContentService.updateAuditStatus(contentId, auditStatus, reviewerId, reviewerName, auditComment, reviewerName) > 0);
}
/**
* 更新发布状态
*
* @param contentId 内容ID
* @param publishStatus 发布状态
* @param publishTime 发布时间
* @param updateBy 更新人
* @return 发布结果
*/
@PostMapping("/updatePublishStatus")
@Operation(summary = "更新发布状态", description = "更新发布状态")
@RequireAuth
public CommonResult<Boolean> updatePublishStatus(@RequestParam Long contentId,
@RequestParam Integer publishStatus,
@RequestParam(required = false) String publishTime,
@RequestParam String updateBy) {
return CommonResult.success(cmsContentService.updatePublishStatus(contentId, publishStatus, publishTime, updateBy) > 0);
}
/**
* 增加阅读量
*
* @param contentId 内容ID
* @return 增加结果
*/
@PostMapping("/increaseViewCount/{contentId}")
@Operation(summary = "增加阅读量", description = "增加阅读量")
public CommonResult<Boolean> increaseViewCount(@PathVariable("contentId") Long contentId) {
return CommonResult.success(cmsContentService.increaseViewCount(contentId) > 0);
}
/**
* 通过主键逻辑删除
*
* @param idDto 主键
* @return 删除数据
*/
@PostMapping("/logicDeleteById")
@Operation(summary = "逻辑删除内容", description = "逻辑删除内容")
@RequireAuth
public CommonResult<Boolean> logicDeleteById(@RequestBody IdDto idDto) {
return CommonResult.success(cmsContentService.logicDeleteById(idDto.getId(), "admin") > 0);
}
/**
* 删除数据
*
* @param contentId 主键
* @return 删除数据
*/
@PostMapping("deleteById/{contentId}")
@Operation(summary = "物理删除内容", description = "物理删除内容")
@RequireAuth
public CommonResult<Boolean> deleteById(@PathVariable("contentId") Long contentId) {
return CommonResult.success(cmsContentService.deleteById(contentId) > 0);
}
}

View File

@ -0,0 +1,121 @@
package com.kexue.skills.controller;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.annotation.RequireAuth;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.CmsTag;
import com.kexue.skills.entity.base.IdDto;
import com.kexue.skills.entity.dto.CmsTagDto;
import com.kexue.skills.service.CmsTagService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* (CmsTag)表控制层
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@RestController
@RequestMapping("api/cmsTag")
@Tag(name = "标签管理 Api")
@CrossOrigin(origins = "*")
public class CmsTagController {
/**
* 服务对象
*/
@Resource
private CmsTagService cmsTagService;
/**
* 分页查询
*
* @param queryDto 筛选条件
* @return 查询结果
*/
@PostMapping("/getPageList")
@Operation(summary = "查询分页列表", description = "查询分页列表")
public CommonResult<PageInfo<CmsTag>> getPageList(@RequestBody CmsTagDto queryDto) {
return CommonResult.success(cmsTagService.getPageList(queryDto));
}
/**
* 查询列表
*
* @param queryDto 筛选条件
* @return 查询结果
*/
@PostMapping("/getList")
@Operation(summary = "查询列表", description = "查询列表")
public CommonResult<PageInfo<CmsTag>> getList(@RequestBody CmsTagDto queryDto) {
return CommonResult.success(new PageInfo<>(cmsTagService.getList(queryDto)));
}
/**
* 通过主键查询单条数据
*
* @param tagId 主键
* @return 单条数据
*/
@PostMapping("queryById/{tagId}")
@Operation(summary = "通过ID查询标签", description = "通过ID查询标签")
public CommonResult<CmsTag> queryById(@PathVariable("tagId") Long tagId) {
return CommonResult.success(cmsTagService.queryById(tagId));
}
/**
* 新增数据
*
* @param cmsTag 实体
* @return 新增结果
*/
@PostMapping("/insert")
@Operation(summary = "新增标签", description = "新增标签")
@RequireAuth
public CommonResult<CmsTag> insert(@RequestBody CmsTag cmsTag) {
return CommonResult.success(cmsTagService.insert(cmsTag));
}
/**
* 编辑数据
*
* @param cmsTag 实体
* @return 编辑结果
*/
@PostMapping("/update")
@Operation(summary = "更新标签", description = "更新标签")
@RequireAuth
public CommonResult<CmsTag> update(@RequestBody CmsTag cmsTag) {
return CommonResult.success(cmsTagService.update(cmsTag));
}
/**
* 通过主键逻辑删除
*
* @param idDto 主键
* @return 删除数据
*/
@PostMapping("/logicDeleteById")
@Operation(summary = "逻辑删除标签", description = "逻辑删除标签")
@RequireAuth
public CommonResult<Boolean> logicDeleteById(@RequestBody IdDto idDto) {
return CommonResult.success(cmsTagService.logicDeleteById(idDto.getId(), "admin") > 0);
}
/**
* 删除数据
*
* @param tagId 主键
* @return 删除数据
*/
@PostMapping("deleteById/{tagId}")
@Operation(summary = "物理删除标签", description = "物理删除标签")
@RequireAuth
public CommonResult<Boolean> deleteById(@PathVariable("tagId") Long tagId) {
return CommonResult.success(cmsTagService.deleteById(tagId) > 0);
}
}

View File

@ -0,0 +1,123 @@
package com.kexue.skills.controller;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.request.UploadResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
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.nio.file.StandardCopyOption;
/**
* @author 维哥
* @Description
* @create 2025-02-27 10:55
*/
@RestController
@RequestMapping("api/common")
@Tag(name = "公共 Api")
@CrossOrigin(origins = "*")
@Slf4j
public class CommonController {
private static final String FILE_UPLOAD_DIR = "/data/service/hyxp-portal/upload/file/";
private static final String IMG_UPLOAD_DIR = "/data/service/hyxp-portal/upload/images/";
/**
* 文件上传接口
* URL: http://localhost:8080/common/uploadFile
* Method: POST
* Body: form-data
* Key: file
* Value: 选择一个文件进行上传
* @param file
* @return
*/
@PostMapping("/uploadFile")
@Operation(summary = "文件上传", description = "文件上传接口")
public CommonResult<UploadResponse> uploadFile(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return CommonResult.failed("文件为空,请选择文件后再上传");
}
try {
// 创建上传目录如果不存在
Path uploadPath = Paths.get(FILE_UPLOAD_DIR);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
// 构建文件保存路径
Path filePath = uploadPath.resolve(file.getOriginalFilename());
// 保存文件
Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
UploadResponse uploadResponse = new UploadResponse();
uploadResponse.setFileName(file.getOriginalFilename());
uploadResponse.setFileUrl("/upload/file/" + file.getOriginalFilename());
return CommonResult.success(uploadResponse);
} catch (IOException e) {
e.printStackTrace();
return CommonResult.failed("文件上传失败: " + e.getMessage());
}
}
/**
* 图片上传接口
* URL: http://localhost:8080/common/uploadImage
* Method: POST
* Body: form-data
* Key: file
* Value: 选择一个图片文件进行上传
* @param image
* @return
*/
@PostMapping("/uploadImage")
@Operation(summary = "图片上传", description = "图片上传接口")
public CommonResult<UploadResponse> uploadImage(@RequestParam("image") MultipartFile image) {
if (image.isEmpty()) {
return CommonResult.failed("图片为空,请选择图片后再上传");
}
// 检查文件是否为图片
if (!image.getContentType().startsWith("image")) {
return CommonResult.failed("上传的文件不是图片");
}
try {
// 创建上传目录如果不存在
Path uploadPath = Paths.get(IMG_UPLOAD_DIR);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
// 构建文件保存路径
Path filePath = uploadPath.resolve(image.getOriginalFilename());
// 保存文件
Files.copy(image.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
UploadResponse uploadResponse = new UploadResponse();
uploadResponse.setFileName(image.getOriginalFilename());
uploadResponse.setFileUrl("/upload/images/" + image.getOriginalFilename());
return CommonResult.success(uploadResponse);
} catch (IOException e) {
e.printStackTrace();
return CommonResult.failed("图片上传失败: " + e.getMessage());
}
}
// CommonController.java 中新增接口
}

View File

@ -0,0 +1,107 @@
package com.kexue.skills.controller;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.annotation.RequireAuth;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.ContentPurchase;
import com.kexue.skills.entity.dto.ContentPurchaseDto;
import com.kexue.skills.service.ContentPurchaseService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* (ContentPurchase)表控制层
* 内容购买控制器
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Tag(name = "内容购买管理 Api")
@RestController
@RequestMapping("/api/contentPurchase")
public class ContentPurchaseController {
/**
* 服务对象
*/
@Resource
private ContentPurchaseService contentPurchaseService;
/**
* 分页查询
*
* @param queryDto 查询参数
* @return 分页结果
*/
@Operation(summary = "分页查询内容购买记录", description = "分页查询内容购买记录")
@PostMapping("/pageList")
@RequireAuth
public CommonResult<PageInfo<ContentPurchase>> getPageList(@RequestBody ContentPurchaseDto queryDto) {
return CommonResult.success(this.contentPurchaseService.getPageList(queryDto));
}
/**
* 查询列表
*
* @param queryDto 查询参数
* @return 列表结果
*/
@Operation(summary = "查询内容购买记录列表", description = "查询内容购买记录列表")
@PostMapping("/list")
@RequireAuth
public CommonResult<List<ContentPurchase>> getList(@RequestBody ContentPurchaseDto queryDto) {
return CommonResult.success(this.contentPurchaseService.getList(queryDto));
}
/**
* 通过主键查询单条数据
*
* @param purchaseId 主键
* @return 单条数据
*/
@Operation(summary = "通过ID查询内容购买记录", description = "通过ID查询内容购买记录")
@PostMapping("/queryById/{purchaseId}")
@RequireAuth
public CommonResult<ContentPurchase> queryById(@Parameter(description = "购买记录ID") @PathVariable("purchaseId") Long purchaseId) {
return CommonResult.success(this.contentPurchaseService.queryById(purchaseId));
}
/**
* 购买内容
*
* @param userId 用户ID
* @param contentId 内容ID
* @param payType 支付方式1.余额支付 2.积分支付
* @return 购买结果
*/
@Operation(summary = "购买内容", description = "购买内容")
@PostMapping("/purchase")
@RequireAuth
public CommonResult<ContentPurchase> purchaseContent(
@Parameter(description = "用户ID") @RequestParam("userId") Long userId,
@Parameter(description = "内容ID") @RequestParam("contentId") Long contentId,
@Parameter(description = "支付方式1.余额支付 2.积分支付") @RequestParam("payType") Integer payType) {
return CommonResult.success(this.contentPurchaseService.purchaseContent(userId, contentId, payType));
}
/**
* 检查用户是否有权限访问内容
*
* @param userId 用户ID
* @param contentId 内容ID
* @return 是否有权限
*/
@Operation(summary = "检查内容访问权限", description = "检查内容访问权限")
@PostMapping("/checkPermission")
@RequireAuth
public CommonResult<Boolean> checkAccessPermission(
@Parameter(description = "用户ID") @RequestParam("userId") Long userId,
@Parameter(description = "内容ID") @RequestParam("contentId") Long contentId) {
boolean hasPermission = this.contentPurchaseService.checkAccessPermission(userId, contentId);
return CommonResult.success(hasPermission);
}
}

View File

@ -0,0 +1,59 @@
package com.kexue.skills.controller;
import com.kexue.skills.annotation.PreventDuplicateSubmission;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.SysUser;
import com.kexue.skills.entity.request.LoginDto;
import com.kexue.skills.entity.request.LoginUserDto;
import com.kexue.skills.service.SysUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* (SysUser)表控制层
*
* @author 王志维
* @since 2024-04-13 01:25:22
*/
@RestController
@RequestMapping("api/login")
@CrossOrigin(origins = "*")
@Tag(name = "登录|登出 Api")
public class LoginController {
/**
* 服务对象
*/
@Resource
private SysUserService sysUserService;
/**
* 用户登录
*
* @param loginDto 登录信息
* @return 登录结果
*/
@PostMapping("/do")
@Operation(summary = "用户登录", description = "用户登录")
@PreventDuplicateSubmission
public CommonResult<LoginUserDto> login(@RequestBody LoginDto loginDto) {
return CommonResult.success(sysUserService.login(loginDto));
}
/**
* 用户登出
*
* @return 登出结果
*/
@PostMapping("/logout")
@Operation(summary = "用户登出", description = "用户登出")
public CommonResult<String> logout() {
// 使用Sa-Token登出
cn.dev33.satoken.stp.StpUtil.logout();
return CommonResult.success("登出成功");
}
}

View File

@ -0,0 +1,92 @@
//package com.kexue.skills.controller;
//
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.stereotype.Controller;
//import org.springframework.ui.Model;
//import org.springframework.web.bind.annotation.GetMapping;
//
//import javax.annotation.Resource;
//import jakarta.servlet.http.HttpServletRequest;
//
///**
// * 所有页面controller再这里声明
// */
//@Controller
//@Slf4j
//public class PageController {
//
// @Resource
//// private BizCardService bizCardService;
//
//// @GetMapping("")
//// public String goHome(HttpServletRequest request, Model model) {
//// model.addAttribute("baseUrl",getServerInfo(request));
//// try {
//// BizCardDto bizCardDto = bizCardService.queryById(1L);
//// if (bizCardDto != null && bizCardDto.getBizCardProducts() != null) {
//// model.addAttribute("bizCardProducts",bizCardDto.getBizCardProducts());
//// } else {
//// model.addAttribute("bizCardProducts",Collections.emptyList());
//// }
//// } catch (Exception e) {
//// log.error("Error fetching bizCardDto: ", e);
//// model.addAttribute("",Collections.emptyList());
//// }
//// return "index";
//// }
///*
//
// @GetMapping("/portal")
// public String portal(HttpServletRequest request, Model model) {
// model.addAttribute("baseUrl",getServerInfo(request));
// try {
// BizCardDto bizCardDto = bizCardService.queryById(1);
// if (bizCardDto != null && bizCardDto.getBizCardProducts() != null) {
// model.addAttribute("bizCardProducts",bizCardDto.getBizCardProducts());
// } else {
// model.addAttribute("bizCardProducts",Collections.emptyList());
// }
// } catch (Exception e) {
// log.error("Error fetching bizCardDto: ", e);
// model.addAttribute("",Collections.emptyList());
// }
// return "index";
// }
//*/
//
// @GetMapping("/login")
// public String login(HttpServletRequest request, Model model) {
// model.addAttribute("baseUrl",getServerInfo(request));
// return "login";
// }
//
// @GetMapping("/main")
// public String main(HttpServletRequest request, Model model) {
// model.addAttribute("baseUrl",getServerInfo(request));
// return "main";
// }
//
// @GetMapping("/dashboard")
// public String dashboard(HttpServletRequest request, Model model) {
// model.addAttribute("baseUrl",getServerInfo(request));
// return "dashboard";
// }
//
//
// @GetMapping("/orderManage")
// public String orderManage(HttpServletRequest request, Model model) {
// model.addAttribute("baseUrl",getServerInfo(request));
// return "dashboard";
// }
//
//
// //写一个获取服务器ip端口上下文路径的函数
// public String getServerInfo(HttpServletRequest request) {
// StringBuilder sb = new StringBuilder();
// sb.append("http://").append(request.getServerName())
// .append(":").append(request.getServerPort())
// .append(request.getContextPath());
// return sb.toString();
// }
//
//}

View File

@ -0,0 +1,85 @@
package com.kexue.skills.controller;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.annotation.RequireAuth;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.PaymentOrder;
import com.kexue.skills.entity.dto.PaymentOrderDto;
import com.kexue.skills.service.PaymentOrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* (PaymentOrder)表控制层
* 支付订单管理控制器
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Tag(name = "支付订单管理 Api")
@RestController
@RequestMapping("/api/paymentOrder")
public class PaymentOrderController {
/**
* 服务对象
*/
@Resource
private PaymentOrderService paymentOrderService;
/**
* 分页查询
*
* @param queryDto 查询参数
* @return 分页结果
*/
@Operation(summary = "分页查询支付订单", description = "分页查询支付订单")
@PostMapping("/pageList")
@RequireAuth
public CommonResult<PageInfo<PaymentOrder>> getPageList(@RequestBody PaymentOrderDto queryDto) {
return CommonResult.success(this.paymentOrderService.getPageList(queryDto));
}
/**
* 查询列表
*
* @param queryDto 查询参数
* @return 列表结果
*/
@Operation(summary = "查询支付订单列表", description = "查询支付订单列表")
@PostMapping("/list")
@RequireAuth
public CommonResult<List<PaymentOrder>> getList(@RequestBody PaymentOrderDto queryDto) {
return CommonResult.success(this.paymentOrderService.getList(queryDto));
}
/**
* 通过主键查询单条数据
*
* @param orderId 主键
* @return 单条数据
*/
@Operation(summary = "通过ID查询支付订单", description = "通过ID查询支付订单")
@PostMapping("/queryById/{orderId}")
@RequireAuth
public CommonResult<PaymentOrder> queryById(@Parameter(description = "订单ID") @PathVariable("orderId") Long orderId) {
return CommonResult.success(this.paymentOrderService.queryById(orderId));
}
/**
* 通过订单号查询单条数据
*
* @param orderNo 订单号
* @return 单条数据
*/
@Operation(summary = "通过订单号查询支付订单", description = "通过订单号查询支付订单")
@PostMapping("/queryByOrderNo")
@RequireAuth
public CommonResult<PaymentOrder> queryByOrderNo(@Parameter(description = "订单号") @RequestParam("orderNo") String orderNo) {
return CommonResult.success(this.paymentOrderService.queryByOrderNo(orderNo));
}
}

View File

@ -0,0 +1,85 @@
package com.kexue.skills.controller;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.annotation.RequireAuth;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.PointsAccount;
import com.kexue.skills.entity.dto.PointsAccountDto;
import com.kexue.skills.service.PointsAccountService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* (PointsAccount)表控制层
* 积分账户管理控制器
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Tag(name = "积分账户管理 Api")
@RestController
@RequestMapping("/api/pointsAccount")
public class PointsAccountController {
/**
* 服务对象
*/
@Resource
private PointsAccountService pointsAccountService;
/**
* 分页查询
*
* @param queryDto 查询参数
* @return 分页结果
*/
@Operation(summary = "分页查询积分账户", description = "分页查询积分账户")
@PostMapping("/pageList")
@RequireAuth
public CommonResult<PageInfo<PointsAccount>> getPageList(@RequestBody PointsAccountDto queryDto) {
return CommonResult.success(this.pointsAccountService.getPageList(queryDto));
}
/**
* 查询列表
*
* @param queryDto 查询参数
* @return 列表结果
*/
@Operation(summary = "查询积分账户列表", description = "查询积分账户列表")
@PostMapping("/list")
@RequireAuth
public CommonResult<List<PointsAccount>> getList(@RequestBody PointsAccountDto queryDto) {
return CommonResult.success(this.pointsAccountService.getList(queryDto));
}
/**
* 通过主键查询单条数据
*
* @param accountId 主键
* @return 单条数据
*/
@Operation(summary = "通过ID查询积分账户", description = "通过ID查询积分账户")
@PostMapping("/queryById/{accountId}")
@RequireAuth
public CommonResult<PointsAccount> queryById(@Parameter(description = "账户ID") @PathVariable("accountId") Long accountId) {
return CommonResult.success(this.pointsAccountService.queryById(accountId));
}
/**
* 通过用户ID查询单条数据
*
* @param userId 用户ID
* @return 单条数据
*/
@Operation(summary = "通过用户ID查询积分账户", description = "通过用户ID查询积分账户")
@PostMapping("/queryByUserId/{userId}")
@RequireAuth
public CommonResult<PointsAccount> queryByUserId(@Parameter(description = "用户ID") @PathVariable("userId") Long userId) {
return CommonResult.success(this.pointsAccountService.queryByUserId(userId));
}
}

View File

@ -0,0 +1,123 @@
package com.kexue.skills.controller;
import com.kexue.skills.entity.SysDict;
import com.kexue.skills.entity.dto.SysDictDto;
import com.kexue.skills.service.SysDictService;
import org.springframework.web.bind.annotation.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.annotation.Resource;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.base.IdDto;
import java.util.List;
import java.util.Map;
/**
* 系统字典表(SysDict)表控制层
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@RestController
@RequestMapping("api/sysDict")
@Tag(name = "系统字典 Api")
@CrossOrigin(origins = "*")
public class SysDictController {
/**
* 服务对象
*/
@Resource
private SysDictService sysDictService;
/**
* 分页查询
*
* @param queryDto 筛选条件
* @return 查询结果
*/
@PostMapping("/getPageList")
@Operation(summary = "查询分页列表", description = "查询分页列表")
public CommonResult<PageInfo<SysDict>> getPageList(@RequestBody SysDictDto queryDto) {
return CommonResult.success(sysDictService.getPageList(queryDto));
}
/**
* 通过主键查询单条数据
*
* @param id 主键
* @return 单条数据
*/
@PostMapping("queryById/{id}")
@Operation(summary = "通过ID查询字典", description = "通过ID查询字典")
public CommonResult<SysDict> queryById(@PathVariable("id") Long id) {
return CommonResult.success(sysDictService.queryById(id));
}
/**
* 新增数据
*
* @param SysDict 实体
* @return 新增结果
*/
@PostMapping("/insert")
@Operation(summary = "新增字典", description = "新增字典")
public CommonResult<SysDict> insert(@RequestBody SysDict SysDict) {
return CommonResult.success(sysDictService.insert(SysDict));
}
/**
* 编辑数据
*
* @param SysDict 实体
* @return 编辑结果
*/
@PostMapping("/update")
@Operation(summary = "更新字典", description = "更新字典")
public CommonResult<SysDict> update(@RequestBody SysDict SysDict) {
return CommonResult.success(sysDictService.update(SysDict));
}
/**
* 删除数据
*
* @param id
* @return 删除数据
*/
@PostMapping("deleteById/{id}")
@Operation(summary = "删除字典", description = "删除字典")
public CommonResult<Boolean> deleteById(@PathVariable("id") Long id) {
return CommonResult.success(sysDictService.deleteById(id));
}
/**
* 查询所有的dictCode
*/
@GetMapping("dictCodeList")
@Operation(summary = "查询所有字典编码", description = "查询所有字典编码")
public CommonResult<List<SysDict>> getAllDictCode() {
return CommonResult.success(sysDictService.getAllDictCode());
}
/**
* 查询所有字典映射
*
*/
@GetMapping("allDictMap")
@Operation(summary = "查询所有字典映射", description = "查询所有字典映射")
public CommonResult<Map<String,List<SysDict>>> getAllDictMap() {
return CommonResult.success(sysDictService.getAllDictMap());
}
@GetMapping("{dictCode}")
@Operation(summary = "通过字典编码查询字典列表", description = "通过字典编码查询字典列表")
public CommonResult<List<SysDict>> getListByDictCode(@PathVariable("dictCode") String dictCode) {
return CommonResult.success(sysDictService.getListByDictCode(dictCode));
}
@PostMapping("getDictListByDictCode")
@Operation(summary = "通过字典编码查询字典列表", description = "通过字典编码查询字典列表")
public CommonResult<List<SysDict>> getDictListByDictCode(@RequestBody SysDict sysDict) {
return CommonResult.success(sysDictService.getListByDictCode(sysDict.getDictCode()));
}
}

View File

@ -0,0 +1,89 @@
package com.kexue.skills.controller;
import com.kexue.skills.entity.SysLog;
import com.kexue.skills.entity.dto.SysLogDto;
import com.kexue.skills.service.SysLogService;
import org.springframework.web.bind.annotation.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.annotation.Resource;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.base.IdDto;
/**
* (SysLog)表控制层
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@RestController
@RequestMapping("api/sysLog")
@Tag(name = "系统日志 Api")
@CrossOrigin(origins = "*")
public class SysLogController {
/**
* 服务对象
*/
@Resource
private SysLogService sysLogService;
/**
* 分页查询
*
* @param queryDto 筛选条件
* @return 查询结果
*/
@PostMapping("/getPageList")
@Operation(summary = "查询分页列表", description = "查询分页列表")
public CommonResult<PageInfo<SysLog>> getPageList(@RequestBody SysLogDto queryDto) {
return CommonResult.success(sysLogService.getPageList(queryDto));
}
/**
* 通过主键查询单条数据
*
* @param id 主键
* @return 单条数据
*/
@PostMapping("queryById/{id}")
@Operation(summary = "通过ID查询日志", description = "通过ID查询日志")
public CommonResult<SysLog> queryById(@PathVariable("id") Long id) {
return CommonResult.success(sysLogService.queryById(id));
}
/**
* 新增数据
*
* @param SysLog 实体
* @return 新增结果
*/
@PostMapping("/insert")
@Operation(summary = "新增日志", description = "新增日志")
public CommonResult<SysLog> insert(@RequestBody SysLog SysLog) {
return CommonResult.success(sysLogService.insert(SysLog));
}
/**
* 编辑数据
*
* @param SysLog 实体
* @return 编辑结果
*/
@PostMapping("/update")
@Operation(summary = "更新日志", description = "更新日志")
public CommonResult<SysLog> update(@RequestBody SysLog SysLog) {
return CommonResult.success(sysLogService.update(SysLog));
}
/**
* 删除数据
*
* @param id
* @return 删除数据
*/
@PostMapping("deleteById/{id}")
@Operation(summary = "删除日志", description = "删除日志")
public CommonResult<Boolean> deleteById(@PathVariable("id") Long id) {
return CommonResult.success(sysLogService.deleteById(id));
}
}

View File

@ -0,0 +1,89 @@
package com.kexue.skills.controller;
import com.kexue.skills.entity.SysMenu;
import com.kexue.skills.entity.dto.SysMenuDto;
import com.kexue.skills.service.SysMenuService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.base.IdDto;
/**
* (SysMenu)表控制层
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@RestController
@RequestMapping("api/sysMenu")
@Tag(name = "系统菜单 Api")
@CrossOrigin(origins = "*")
public class SysMenuController {
/**
* 服务对象
*/
@Resource
private SysMenuService sysMenuService;
/**
* 分页查询
*
* @param queryDto 筛选条件
* @return 查询结果
*/
@PostMapping("/getPageList")
@Operation(summary = "查询分页列表",description = "查询分页列表")
public CommonResult<PageInfo<SysMenu>> getPageList(@RequestBody SysMenuDto queryDto) {
return CommonResult.success(sysMenuService.getPageList(queryDto));
}
/**
* 通过主键查询单条数据
*
* @param id 主键
* @return 单条数据
*/
@PostMapping("queryById/{id}")
@Operation(summary = "通过ID查询菜单", description = "通过ID查询菜单")
public CommonResult<SysMenu> queryById(@PathVariable("id") Long id) {
return CommonResult.success(sysMenuService.queryById(id));
}
/**
* 新增数据
*
* @param SysMenu 实体
* @return 新增结果
*/
@PostMapping("/insert")
@Operation(summary = "新增菜单", description = "新增菜单")
public CommonResult<SysMenu> insert(@RequestBody SysMenu SysMenu) {
return CommonResult.success(sysMenuService.insert(SysMenu));
}
/**
* 编辑数据
*
* @param SysMenu 实体
* @return 编辑结果
*/
@PostMapping("/update")
@Operation(summary = "更新菜单", description = "更新菜单")
public CommonResult<SysMenu> update(@RequestBody SysMenu SysMenu) {
return CommonResult.success(sysMenuService.update(SysMenu));
}
/**
* 删除数据
*
* @param id
* @return 删除数据
*/
@PostMapping("deleteById/{id}")
@Operation(summary = "删除菜单", description = "删除菜单")
public CommonResult<Boolean> deleteById(@PathVariable("id") Long id) {
return CommonResult.success(sysMenuService.deleteById(id));
}
}

View File

@ -0,0 +1,89 @@
package com.kexue.skills.controller;
import com.kexue.skills.entity.SysRole;
import com.kexue.skills.entity.dto.SysRoleDto;
import com.kexue.skills.service.SysRoleService;
import org.springframework.web.bind.annotation.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.annotation.Resource;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.base.IdDto;
/**
* (SysRole)表控制层
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@RestController
@RequestMapping("api/sysRole")
@Tag(name = "系统角色 Api")
@CrossOrigin(origins = "*")
public class SysRoleController {
/**
* 服务对象
*/
@Resource
private SysRoleService sysRoleService;
/**
* 分页查询
*
* @param queryDto 筛选条件
* @return 查询结果
*/
@PostMapping("/getPageList")
@Operation(summary = "查询分页列表", description = "查询分页列表")
public CommonResult<PageInfo<SysRole>> getPageList(@RequestBody SysRoleDto queryDto) {
return CommonResult.success(sysRoleService.getPageList(queryDto));
}
/**
* 通过主键查询单条数据
*
* @param id 主键
* @return 单条数据
*/
@PostMapping("queryById/{id}")
@Operation(summary = "通过ID查询角色", description = "通过ID查询角色")
public CommonResult<SysRole> queryById(@PathVariable("id") Long id) {
return CommonResult.success(sysRoleService.queryById(id));
}
/**
* 新增数据
*
* @param SysRole 实体
* @return 新增结果
*/
@PostMapping("/insert")
@Operation(summary = "新增角色", description = "新增角色")
public CommonResult<SysRole> insert(@RequestBody SysRole SysRole) {
return CommonResult.success(sysRoleService.insert(SysRole));
}
/**
* 编辑数据
*
* @param SysRole 实体
* @return 编辑结果
*/
@PostMapping("/update")
@Operation(summary = "更新角色", description = "更新角色")
public CommonResult<SysRole> update(@RequestBody SysRole SysRole) {
return CommonResult.success(sysRoleService.update(SysRole));
}
/**
* 删除数据
*
* @param id
* @return 删除数据
*/
@PostMapping("deleteById/{id}")
@Operation(summary = "删除角色", description = "删除角色")
public CommonResult<Boolean> deleteById(@PathVariable("id") Long id) {
return CommonResult.success(sysRoleService.deleteById(id));
}
}

View File

@ -0,0 +1,195 @@
package com.kexue.skills.controller;
import com.kexue.skills.annotation.RequireAuth;
import com.kexue.skills.entity.SysUser;
import com.kexue.skills.entity.dto.SysUserDto;
import com.kexue.skills.entity.request.ResetPasswordDto;
import com.kexue.skills.entity.request.ResetPwdDto;
import com.kexue.skills.exception.BizException;
import com.kexue.skills.service.SysUserService;
import org.springframework.web.bind.annotation.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import com.kexue.skills.common.CacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.base.IdDto;
/**
* (SysUser)表控制层
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@RestController
@RequestMapping("api/sysUser")
@Tag(name = "用户管理 Api")
@CrossOrigin(origins = "*")
public class SysUserController {
/**
* 服务对象
*/
@Resource
private SysUserService sysUserService;
/**
* Redis模板
*/
@Resource
private RedisTemplate<String, String> redisTemplate;
/**
* 分页查询
*
* @param queryDto 筛选条件
* @return 查询结果
*/
@PostMapping("/getPageList")
@Operation(summary = "查询分页列表", description = "查询分页列表")
public CommonResult<PageInfo<SysUser>> getPageList(@RequestBody SysUserDto queryDto) {
return CommonResult.success(sysUserService.getPageList(queryDto));
}
/**
* 通过主键查询单条数据
*
* @param id 主键
* @return 单条数据
*/
@PostMapping("queryById/{id}")
@Operation(summary = "通过ID查询用户", description = "通过ID查询用户")
public CommonResult<SysUser> queryById(@PathVariable("id") Long id) {
return CommonResult.success(sysUserService.queryById(id));
}
/**
* 新增数据
*
* @param SysUser 实体
* @return 新增结果
*/
@PostMapping("/insert")
@Operation(summary = "新增用户", description = "新增用户")
public CommonResult<SysUser> insert(@RequestBody SysUser SysUser) {
return CommonResult.success(sysUserService.insert(SysUser));
}
/**
* 编辑数据
*
* @param SysUser 实体
* @return 编辑结果
*/
@PostMapping("/update")
@Operation(summary = "更新用户", description = "更新用户")
public CommonResult<SysUser> update(@RequestBody SysUser SysUser) {
return CommonResult.success(sysUserService.update(SysUser));
}
/**
* 删除数据
*
* @param id
* @return 删除数据
*/
@PostMapping("deleteById/{id}")
@Operation(summary = "通过ID删除用户", description = "通过ID删除用户")
public CommonResult<Boolean> deleteById(@PathVariable("id") Long id) {
return CommonResult.success(sysUserService.deleteById(id));
}
@PostMapping("deleteByIdDto")
@Operation(summary = "通过ID删除用户", description = "通过ID删除用户")
public CommonResult<Boolean> deleteByIdDto(@RequestBody IdDto idDto) {
return CommonResult.success(sysUserService.deleteById(idDto.getId()));
}
@PostMapping("/resetPassword")
@Operation(summary = "管理员帮助用户重置密码", description = "管理员帮助用户重置密码")
@RequireAuth
public CommonResult<Boolean> resetPasswordByAdmin(@RequestBody ResetPasswordDto resetPasswordDto, HttpServletRequest request) {
// 从请求头中获取token
String token = request.getHeader("Authorization");
if (token == null || token.isEmpty()) {
throw new BizException("请先登录认证后操作");
}
// 从缓存中获取当前登录用户
String username = CacheManager.getUsernameFromToken(token);
if (username == null) {
throw new BizException("无效的token请重新登录");
}
SysUser adminUser = sysUserService.getByUsername(username);
if (adminUser == null) {
throw new BizException("管理员不存在");
}
boolean result = sysUserService.resetPasswordByAdmin(resetPasswordDto);
return CommonResult.success(result);
}
/**
* 重置密码管理员专用通过用户ID
*
* @param resetPwdDto 重置密码请求参数
* @param request HTTP请求
* @return 重置结果
*/
@PostMapping("/resetPwd")
@Operation(summary = "重置密码管理员专用通过用户ID", description = "重置密码管理员专用通过用户ID")
@RequireAuth
public CommonResult<Boolean> resetPwd(@RequestBody ResetPwdDto resetPwdDto, HttpServletRequest request) {
// 从请求头中获取token
String token = request.getHeader("Authorization");
if (token == null || token.isEmpty()) {
throw new BizException("请先登录认证后操作");
}
// 从缓存中获取当前登录用户
String username = CacheManager.getUsernameFromToken(token);
if (username == null) {
throw new BizException("无效的token请重新登录");
}
SysUser adminUser = sysUserService.getByUsername(username);
if (adminUser == null) {
throw new BizException("管理员不存在");
}
// 调用服务层方法重置密码
boolean result = sysUserService.resetPwd(resetPwdDto.getUserId(), resetPwdDto.getNewPassword(), username);
return CommonResult.success(result);
}
/**
* 获取当前登录用户信息
*
* @param request HTTP请求
* @return 当前登录用户信息
*/
@GetMapping("/currentUser")
@Operation(summary = "获取当前登录用户信息", description = "获取当前登录用户信息")
@RequireAuth
public CommonResult<com.kexue.skills.entity.request.LoginUser> currentUser(HttpServletRequest request) {
// 从请求头中获取token
String token = request.getHeader("Authorization");
if (token == null || token.isEmpty()) {
throw new BizException("请先登录认证后操作");
}
// 从Redis缓存中获取LoginUser对象
String loginUserJson = redisTemplate.opsForValue().get("loginUser:" + token);
if (loginUserJson == null || loginUserJson.isEmpty()) {
throw new BizException("无效的token请重新登录");
}
// 解析JSON字符串为LoginUser对象
com.kexue.skills.entity.request.LoginUser loginUser = cn.hutool.json.JSONUtil.toBean(loginUserJson, com.kexue.skills.entity.request.LoginUser.class);
return CommonResult.success(loginUser);
}
}

View File

@ -0,0 +1,89 @@
package com.kexue.skills.controller;
import com.kexue.skills.entity.SysUserRole;
import com.kexue.skills.entity.dto.SysUserRoleDto;
import com.kexue.skills.service.SysUserRoleService;
import org.springframework.web.bind.annotation.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import javax.annotation.Resource;
import com.github.pagehelper.PageInfo;
import com.kexue.skills.common.CommonResult;
import com.kexue.skills.entity.base.IdDto;
/**
* (SysUserRole)表控制层
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@RestController
@RequestMapping("api/sysUserRole")
@Tag(name = "用户角色管理 Api")
@CrossOrigin(origins = "*")
public class SysUserRoleController {
/**
* 服务对象
*/
@Resource
private SysUserRoleService sysUserRoleService;
/**
* 分页查询
*
* @param queryDto 筛选条件
* @return 查询结果
*/
@PostMapping("/getPageList")
@Operation(summary = "查询分页列表", description = "查询分页列表")
public CommonResult<PageInfo<SysUserRole>> getPageList(@RequestBody SysUserRoleDto queryDto) {
return CommonResult.success(sysUserRoleService.getPageList(queryDto));
}
/**
* 通过主键查询单条数据
*
* @param id 主键
* @return 单条数据
*/
@PostMapping("queryById/{id}")
@Operation(summary = "通过ID查询用户角色关联", description = "通过ID查询用户角色关联")
public CommonResult<SysUserRole> queryById(@PathVariable("id") Long id) {
return CommonResult.success(sysUserRoleService.queryById(id));
}
/**
* 新增数据
*
* @param SysUserRole 实体
* @return 新增结果
*/
@PostMapping("/insert")
@Operation(summary = "新增用户角色关联", description = "新增用户角色关联")
public CommonResult<SysUserRole> insert(@RequestBody SysUserRole SysUserRole) {
return CommonResult.success(sysUserRoleService.insert(SysUserRole));
}
/**
* 编辑数据
*
* @param SysUserRole 实体
* @return 编辑结果
*/
@PostMapping("/update")
@Operation(summary = "更新用户角色关联", description = "更新用户角色关联")
public CommonResult<SysUserRole> update(@RequestBody SysUserRole SysUserRole) {
return CommonResult.success(sysUserRoleService.update(SysUserRole));
}
/**
* 删除数据
*
* @param id
* @return 删除数据
*/
@PostMapping("deleteById/{id}")
@Operation(summary = "删除用户角色关联", description = "删除用户角色关联")
public CommonResult<Boolean> deleteById(@PathVariable("id") Long id) {
return CommonResult.success(sysUserRoleService.deleteById(id));
}
}

View File

@ -0,0 +1,49 @@
package com.kexue.skills.entity;
import java.math.BigDecimal;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (Account)实体类
* 账户表记录用户的账户信息
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class Account extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description ="主键ID")
private Long accountId;
@Schema(description ="用户ID")
private Long userId;
@Schema(description ="用户名")
private String userName;
@Schema(description ="账户余额")
private BigDecimal balance;
@Schema(description ="冻结金额")
private BigDecimal frozenAmount;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="更新时间")
private Date updateTime;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,79 @@
package com.kexue.skills.entity;
import java.math.BigDecimal;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (AccountTransaction)实体类
* 账户流水表记录用户的账户交易记录
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class AccountTransaction extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description ="主键ID")
private Long transactionId;
@Schema(description ="用户ID")
private Long userId;
@Schema(description ="用户名")
private String userName;
@Schema(description ="交易类型1.充值 2.提现 3.购买内容 4.退款 5.其他")
private Integer transactionType;
@Schema(description ="交易金额")
private BigDecimal amount;
@Schema(description ="交易前余额")
private BigDecimal beforeBalance;
@Schema(description ="交易后余额")
private BigDecimal afterBalance;
@Schema(description ="交易状态1.成功 2.失败 3.处理中")
private Integer status;
@Schema(description ="交易单号")
private String transactionNo;
@Schema(description ="支付方式1.微信 2.支付宝 3.余额支付")
private Integer payType;
@Schema(description ="关联业务ID")
private Long businessId;
@Schema(description ="业务类型")
private String businessType;
@Schema(description ="交易备注")
private String remark;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="更新时间")
private Date updateTime;
@Schema(description ="创建人")
private String createBy;
@Schema(description ="更新人")
private String updateBy;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,59 @@
package com.kexue.skills.entity;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (CmsCategory)实体类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class CmsCategory extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description ="主键ID")
private Long categoryId;
@Schema(description ="分类名称")
private String categoryName;
@Schema(description ="父分类ID")
private Long parentId;
@Schema(description ="分类层级")
private Integer level;
@Schema(description ="排序")
private Integer sort;
@Schema(description ="状态1启用2禁用")
private Integer status;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="更新时间")
private Date updateTime;
@Schema(description ="创建人")
private String createBy;
@Schema(description ="更新人")
private String updateBy;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
@Schema(description ="子分类列表")
private java.util.List<CmsCategory> subCategoryList;
}

View File

@ -0,0 +1,133 @@
package com.kexue.skills.entity;
import java.math.BigDecimal;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (CmsContent)实体类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class CmsContent extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description ="主键ID")
private Long contentId;
@Schema(description ="标题")
private String title;
@Schema(description ="是否是官方0否1是")
private Boolean isOfficial;
@Schema(description ="分类ID")
private Long categoryId;
@Schema(description ="图标")
private String icon;
@Schema(description ="背景")
private String background;
@Schema(description ="文件URL")
private String fileUrl;
@Schema(description ="内容摘要")
private String summary;
@Schema(description ="分享数量")
private Integer shareCount;
@Schema(description ="点赞量")
private Integer likeCount;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@Schema(description ="付费金额")
private BigDecimal price;
@Schema(description ="内容类型1文章2视频3图片")
private Integer contentType;
@Schema(description ="父分类ID")
private Long parentCategoryId;
@Schema(description ="内容详情")
private String content;
@Schema(description ="封面图片")
private String coverImage;
@Schema(description ="作者ID")
private Long authorId;
@Schema(description ="作者名称")
private String authorName;
@Schema(description ="审核人ID")
private Long reviewerId;
@Schema(description ="审核人名称")
private String reviewerName;
@Schema(description ="审核状态1草稿2待审核3审核通过4审核拒绝")
private Integer auditStatus;
@Schema(description ="审核意见")
private String auditComment;
@Schema(description ="发布状态1未发布2已发布3已下架")
private Integer publishStatus;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="发布时间")
private Date publishTime;
@Schema(description ="阅读量")
private Integer viewCount;
@Schema(description ="评论量")
private Integer commentCount;
@Schema(description ="排序")
private Integer sort;
@Schema(description ="所需积分")
private Integer requiredPoints;
@Schema(description ="是否支持积分支付0不支持1支持")
private Integer supportPointsPay;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="更新时间")
private Date updateTime;
@Schema(description ="创建人")
private String createBy;
@Schema(description ="更新人")
private String updateBy;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
@Schema(description ="子分类列表")
private java.util.List<CmsCategory> subCategoryList;
@Schema(description ="是否付费0免费1付费")
private Integer isPaid;
@Schema(description ="副标题")
private String subtitle;
}

View File

@ -0,0 +1,53 @@
package com.kexue.skills.entity;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (CmsTag)实体类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class CmsTag extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description ="主键ID")
private Long tagId;
@Schema(description ="标签名称")
private String tagName;
@Schema(description ="标签描述")
private String description;
@Schema(description ="使用次数")
private Integer useCount;
@Schema(description ="状态1启用2禁用")
private Integer status;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="更新时间")
private Date updateTime;
@Schema(description ="创建人")
private String createBy;
@Schema(description ="更新人")
private String updateBy;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,64 @@
package com.kexue.skills.entity;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (ContentPurchase)实体类
* 内容购买记录表记录用户购买的内容信息
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class ContentPurchase extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description ="主键ID")
private Long purchaseId;
@Schema(description ="用户ID")
private Long userId;
@Schema(description ="用户名")
private String userName;
@Schema(description ="内容ID")
private Long contentId;
@Schema(description ="内容标题")
private String contentTitle;
@Schema(description ="购买方式1.余额支付 2.积分支付")
private Integer payType;
@Schema(description ="支付金额")
private java.math.BigDecimal amount;
@Schema(description ="支付积分")
private Integer points;
@Schema(description ="购买状态1.待支付 2.已支付 3.已取消")
private Integer status;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="购买时间")
private Date purchaseTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="更新时间")
private Date updateTime;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,53 @@
package com.kexue.skills.entity;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (Customer)实体类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class Customer extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description ="主键ID")
private Long customerId;
@Schema(description ="客户名称")
private String customerName;
@Schema(description ="联系人")
private String contactPerson;
@Schema(description ="联系电话")
private String contactPhone;
@Schema(description ="地址")
private String address;
@Schema(description ="备注")
private String remark;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="更新时间")
private Date updateTime;
@Schema(description ="是否启用1启用2禁用")
private Integer enable;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,87 @@
package com.kexue.skills.entity;
import java.math.BigDecimal;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (PaymentOrder)实体类
* 支付订单表记录用户的支付请求和支付结果
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class PaymentOrder extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description ="主键ID")
private Long orderId;
@Schema(description ="订单号")
private String orderNo;
@Schema(description ="用户ID")
private Long userId;
@Schema(description ="用户名")
private String userName;
@Schema(description ="支付金额")
private BigDecimal amount;
@Schema(description ="支付方式1.微信 2.支付宝")
private Integer payType;
@Schema(description ="支付状态1.待支付 2.已支付 3.支付失败 4.已取消 5.已退款")
private Integer status;
@Schema(description ="支付渠道订单号")
private String channelOrderNo;
@Schema(description ="商品名称")
private String productName;
@Schema(description ="商品描述")
private String productDesc;
@Schema(description ="关联业务ID")
private Long businessId;
@Schema(description ="业务类型")
private String businessType;
@Schema(description ="支付回调地址")
private String notifyUrl;
@Schema(description ="支付成功跳转地址")
private String returnUrl;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="过期时间")
private Date expireTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="支付时间")
private Date payTime;
@Schema(description ="支付备注")
private String remark;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="更新时间")
private Date updateTime;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,51 @@
package com.kexue.skills.entity;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (PointsAccount)实体类
* 积分账户表记录用户的积分信息
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class PointsAccount extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description ="主键ID")
private Long accountId;
@Schema(description ="用户ID")
private Long userId;
@Schema(description ="用户名")
private String userName;
@Schema(description ="总积分")
private Integer totalPoints;
@Schema(description ="可用积分")
private Integer availablePoints;
@Schema(description ="冻结积分")
private Integer frozenPoints;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="更新时间")
private Date updateTime;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,78 @@
package com.kexue.skills.entity;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (PointsTransaction)实体类
* 积分流水表记录用户的积分变动情况
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class PointsTransaction extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description ="主键ID")
private Long transactionId;
@Schema(description ="用户ID")
private Long userId;
@Schema(description ="用户名")
private String userName;
@Schema(description ="积分变动类型1.获取积分 2.消费积分 3.过期 4.其他")
private Integer transactionType;
@Schema(description ="变动积分")
private Integer points;
@Schema(description ="变动前积分")
private Integer beforePoints;
@Schema(description ="变动后积分")
private Integer afterPoints;
@Schema(description ="交易状态1.成功 2.失败 3.处理中")
private Integer status;
@Schema(description ="交易单号")
private String transactionNo;
@Schema(description ="支付方式1.微信 2.支付宝 3.余额支付")
private Integer payType;
@Schema(description ="关联业务ID")
private Long businessId;
@Schema(description ="业务类型")
private String businessType;
@Schema(description ="备注")
private String remark;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="更新时间")
private Date updateTime;
@Schema(description ="创建人")
private String createBy;
@Schema(description ="更新人")
private String updateBy;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,53 @@
package com.kexue.skills.entity;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (Supplier)实体类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class Supplier extends BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description ="主键ID")
private Long supplierId;
@Schema(description ="供货商名称")
private String supplierName;
@Schema(description ="联系人")
private String contactPerson;
@Schema(description ="联系电话")
private String contactPhone;
@Schema(description ="地址")
private String address;
@Schema(description ="备注")
private String remark;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="更新时间")
private Date updateTime;
@Schema(description ="是否启用1启用2禁用")
private Integer enable;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,47 @@
package com.kexue.skills.entity;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.kexue.skills.entity.base.BaseQueryDto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 系统字典表(SysDict)实体类
*
* @author 王志维
* @since 2025-02-21 23:01:47
*/
@Data
public class SysDict extends BaseEntity implements Serializable {
private static final long serialVersionUID = 754185131264184698L;
@Schema(description ="字典表ID")
private Long id;
@Schema(description ="字典编码")
private String dictCode;
@Schema(description ="字典名称")
private String dictName;
@Schema(description ="字典值中文文本")
private String dictCn;
@Schema(description ="字典值英文文本")
private String dictEn;
@Schema(description ="字典值")
private Object dictValue;
@Schema(description ="字典排序")
private Object sorts;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
}

View File

@ -0,0 +1,48 @@
package com.kexue.skills.entity;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.kexue.skills.entity.base.BaseQueryDto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (SysLog)实体类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class SysLog extends BaseEntity implements Serializable {
private static final long serialVersionUID = -84681351128482970L;
@Schema(description ="主键ID")
private Long logId;
@Schema(description ="用户ID")
private String userId;
@Schema(description ="用户名称")
private String userName;
@Schema(description ="日志类型")
private String logType;
@Schema(description ="日志类容")
private String logContent;
@Schema(description ="服务端IP")
private String serverIp;
@Schema(description ="客户端IP")
private String clientIp;
@Schema(description ="yyyyMMddHHmmss")
private String logTime;
@Schema(description ="备注")
private String note;
}

View File

@ -0,0 +1,48 @@
package com.kexue.skills.entity;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.kexue.skills.entity.base.BaseQueryDto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (SysMenu)实体类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class SysMenu extends BaseEntity implements Serializable {
private static final long serialVersionUID = -34455248020533426L;
@Schema(description ="主键ID")
private Long menuId;
@Schema(description ="为空时表示是子系统")
private Long menuPid;
@Schema(description ="菜单名称")
private String menuName;
@Schema(description ="菜单链接地址")
private String menuSrc;
@Schema(description ="菜单图标")
private String menuIcon;
@Schema(description ="菜单样式")
private String menuStyle;
@Schema(description ="值越小越排在前面")
private Integer sort;
@Schema(description ="备注")
private String note;
@Schema(description ="删除标记")
private Object deleteFlag;
}

View File

@ -0,0 +1,41 @@
package com.kexue.skills.entity;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.kexue.skills.entity.base.BaseQueryDto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (SysRole)实体类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class SysRole extends BaseEntity implements Serializable {
private static final long serialVersionUID = 343002535091443381L;
@Schema(description ="角色ID")
private Long roleId;
@Schema(description ="角色编码")
private String roleCode;
@Schema(description ="角色名称")
private String roleName;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@Schema(description ="备注")
private String remark;
@Schema(description ="删除标记")
private String deleteFlag;
}

View File

@ -0,0 +1,56 @@
package com.kexue.skills.entity;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.kexue.skills.entity.base.BaseQueryDto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (SysUser)实体类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class SysUser extends BaseEntity implements Serializable {
private static final long serialVersionUID = -40877019678009880L;
@Schema(description ="主键ID")
private Long userId;
@Schema(description ="用户登录名称")
private String userName;
@Schema(description ="密码(非明文)")
private String pwd;
@Schema(description ="真实姓名")
private String realName;
@Schema(description ="手机")
private String tel;
@Schema(description ="邮箱")
private String email;
@Schema(description ="加点盐(登录时候要用到的随机数)")
private String salt;
@Schema(description ="备注")
private String remark;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@Schema(description ="是否启用1启用2禁用")
private Integer enable;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,27 @@
package com.kexue.skills.entity;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseEntity;
import com.kexue.skills.entity.base.BaseQueryDto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* (SysUserRole)实体类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class SysUserRole extends BaseEntity implements Serializable {
private static final long serialVersionUID = -52125282568963778L;
@Schema(description ="角色ID")
private Long roleId;
@Schema(description ="用户ID")
private Long userId;
}

View File

@ -0,0 +1,16 @@
package com.kexue.skills.entity.base;
import java.io.Serializable;
import java.util.HashMap;
public class BaseEntity implements Serializable {
private static HashMap map = new HashMap<>();
public void put(String key,Object value){
map.put(key,value);
}
private Object get(String key){
return map.get(key);
}
}

View File

@ -0,0 +1,22 @@
package com.kexue.skills.entity.base;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
@Data
@ApiModel
public class BaseQueryDto implements Serializable {
public static final Integer DEFAULT_PAGE_SIZE = 10;
public static final Integer DEFAULT_CURRENT_PAGE = 1;
@Schema(description ="当前页")
private Integer pageNum;
@Schema(description ="每页数量")
private Integer pageSize;
}

View File

@ -0,0 +1,18 @@
package com.kexue.skills.entity.base;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* @author 维哥
* @Description
* @create 2025-02-21 18:47
*/
@Data
@ApiModel(description = "ID对象")
public class IdDto {
@Schema(description ="主键ID")
private Long id;
}

View File

@ -0,0 +1,23 @@
package com.kexue.skills.entity.dto;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
/**
* (Account)查询DTO类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class AccountDto extends BaseQueryDto {
private Long accountId;
private Long userId;
private String userName;
private Integer deleteFlag;
}

View File

@ -0,0 +1,35 @@
package com.kexue.skills.entity.dto;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
/**
* (AccountTransaction)查询DTO类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class AccountTransactionDto extends BaseQueryDto {
private Long transactionId;
private Long userId;
private String userName;
private Integer transactionType;
private Integer status;
private String transactionNo;
private Integer payType;
private Long businessId;
private String businessType;
private Integer deleteFlag;
}

View File

@ -0,0 +1,29 @@
package com.kexue.skills.entity.dto;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
/**
* (CmsCategory)查询DTO类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class CmsCategoryDto extends BaseQueryDto {
private Long categoryId;
private String categoryName;
private Long parentId;
private Integer level;
private Integer sort;
private Integer status;
private Integer deleteFlag;
}

View File

@ -0,0 +1,41 @@
package com.kexue.skills.entity.dto;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
/**
* (CmsContent)查询DTO类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class CmsContentDto extends BaseQueryDto {
private Long contentId;
private String title;
private Integer contentType;
private Long categoryId;
private Long parentCategoryId;
private Boolean isOfficial;
private Integer shareCount;
private Long authorId;
private String authorName;
private Integer auditStatus;
private Integer publishStatus;
private String createBy;
private Integer deleteFlag;
}

View File

@ -0,0 +1,25 @@
package com.kexue.skills.entity.dto;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
/**
* (CmsTag)查询DTO类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class CmsTagDto extends BaseQueryDto {
private Long tagId;
private String tagName;
private String description;
private Integer status;
private Integer deleteFlag;
}

View File

@ -0,0 +1,68 @@
package com.kexue.skills.entity.dto;
import com.kexue.skills.entity.base.BaseQueryDto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* (ContentPurchase)查询条件封装类
* 内容购买记录查询条件
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class ContentPurchaseDto extends BaseQueryDto {
@Schema(description ="主键ID")
private Long purchaseId;
@Schema(description ="用户ID")
private Long userId;
@Schema(description ="用户名")
private String userName;
@Schema(description ="内容ID")
private Long contentId;
@Schema(description ="内容标题")
private String contentTitle;
@Schema(description ="购买方式1.余额支付 2.积分支付")
private Integer payType;
@Schema(description ="支付金额")
private BigDecimal amount;
@Schema(description ="支付积分")
private Integer points;
@Schema(description ="购买状态1.待支付 2.已支付 3.已取消")
private Integer status;
@Schema(description ="购买时间开始")
private Date purchaseTimeStart;
@Schema(description ="购买时间结束")
private Date purchaseTimeEnd;
@Schema(description ="创建时间开始")
private Date createTimeStart;
@Schema(description ="创建时间结束")
private Date createTimeEnd;
@Schema(description ="更新时间开始")
private Date updateTimeStart;
@Schema(description ="更新时间结束")
private Date updateTimeEnd;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,29 @@
package com.kexue.skills.entity.dto;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
/**
* (Customer)查询DTO类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class CustomerDto extends BaseQueryDto {
private Long customerId;
private String customerName;
private String contactPerson;
private String contactPhone;
private String address;
private Integer enable;
private Integer deleteFlag;
}

View File

@ -0,0 +1,33 @@
package com.kexue.skills.entity.dto;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
/**
* (PaymentOrder)查询DTO类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class PaymentOrderDto extends BaseQueryDto {
private Long orderId;
private String orderNo;
private Long userId;
private String userName;
private Integer payType;
private Integer status;
private Long businessId;
private String businessType;
private Integer deleteFlag;
}

View File

@ -0,0 +1,52 @@
package com.kexue.skills.entity.dto;
import com.kexue.skills.entity.base.BaseQueryDto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
/**
* (PointsAccount)查询条件封装类
* 积分账户查询条件
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class PointsAccountDto extends BaseQueryDto {
@Schema(description ="主键ID")
private Long accountId;
@Schema(description ="用户ID")
private Long userId;
@Schema(description ="用户名")
private String userName;
@Schema(description ="总积分")
private Integer totalPoints;
@Schema(description ="可用积分")
private Integer availablePoints;
@Schema(description ="冻结积分")
private Integer frozenPoints;
@Schema(description ="创建时间开始")
private Date createTimeStart;
@Schema(description ="创建时间结束")
private Date createTimeEnd;
@Schema(description ="更新时间开始")
private Date updateTimeStart;
@Schema(description ="更新时间结束")
private Date updateTimeEnd;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,73 @@
package com.kexue.skills.entity.dto;
import com.kexue.skills.entity.base.BaseQueryDto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.Date;
/**
* (PointsTransaction)查询条件封装类
* 积分交易记录查询条件
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class PointsTransactionDto extends BaseQueryDto {
@Schema(description ="主键ID")
private Long transactionId;
@Schema(description ="用户ID")
private Long userId;
@Schema(description ="用户名")
private String userName;
@Schema(description ="交易类型1.获得积分 2.使用积分")
private Integer transactionType;
@Schema(description ="积分数量")
private Integer points;
@Schema(description ="交易前积分")
private Integer beforePoints;
@Schema(description ="交易后积分")
private Integer afterPoints;
@Schema(description ="状态1.成功 2.失败")
private Integer status;
@Schema(description ="交易单号")
private String transactionNo;
@Schema(description ="支付方式1.微信 2.支付宝 3.余额支付")
private Integer payType;
@Schema(description ="业务ID")
private Long businessId;
@Schema(description ="业务类型")
private String businessType;
@Schema(description ="备注")
private String remark;
@Schema(description ="创建时间开始")
private Date createTimeStart;
@Schema(description ="创建时间结束")
private Date createTimeEnd;
@Schema(description ="更新时间开始")
private Date updateTimeStart;
@Schema(description ="更新时间结束")
private Date updateTimeEnd;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,29 @@
package com.kexue.skills.entity.dto;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
/**
* (Supplier)查询DTO类
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
public class SupplierDto extends BaseQueryDto {
private Long supplierId;
private String supplierName;
private String contactPerson;
private String contactPhone;
private String address;
private Integer enable;
private Integer deleteFlag;
}

View File

@ -0,0 +1,49 @@
package com.kexue.skills.entity.dto;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* 系统字典表(SysDict)实体类Dto
*
* @author 王志维
* @since 2025-02-21 23:01:47
*/
@Data
@ApiModel
public class SysDictDto extends BaseQueryDto implements Serializable {
private static final long serialVersionUID = 890696045006377935L;
@Schema(description ="字典表ID")
private Long id;
@Schema(description ="字典编码")
private String dictCode;
@Schema(description ="字典名称")
private String dictName;
@Schema(description ="字典值中文文本")
private String dictCn;
@Schema(description ="字典值英文文本")
private String dictEn;
@Schema(description ="字典值")
private Object dictValue;
@Schema(description ="字典排序")
private Object sorts;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
}

View File

@ -0,0 +1,50 @@
package com.kexue.skills.entity.dto;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* (SysLog)实体类Dto
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
@ApiModel
public class SysLogDto extends BaseQueryDto implements Serializable {
private static final long serialVersionUID = 439036642073575183L;
@Schema(description ="主键ID")
private Long logId;
@Schema(description ="用户ID")
private String userId;
@Schema(description ="用户名称")
private String userName;
@Schema(description ="日志类型")
private String logType;
@Schema(description ="日志类容")
private String logContent;
@Schema(description ="服务端IP")
private String serverIp;
@Schema(description ="客户端IP")
private String clientIp;
@Schema(description ="yyyyMMddHHmmss")
private String logTime;
@Schema(description ="备注")
private String note;
}

View File

@ -0,0 +1,50 @@
package com.kexue.skills.entity.dto;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* (SysMenu)实体类Dto
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
@ApiModel
public class SysMenuDto extends BaseQueryDto implements Serializable {
private static final long serialVersionUID = 745631748723623384L;
@Schema(description ="主键ID")
private Long menuId;
@Schema(description ="为空时表示是子系统")
private Long menuPid;
@Schema(description ="菜单名称")
private String menuName;
@Schema(description ="菜单链接地址")
private String menuSrc;
@Schema(description ="菜单图标")
private String menuIcon;
@Schema(description ="菜单样式")
private String menuStyle;
@Schema(description ="值越小越排在前面")
private Integer sort;
@Schema(description ="备注")
private String note;
@Schema(description ="删除标记")
private Object deleteFlag;
}

View File

@ -0,0 +1,43 @@
package com.kexue.skills.entity.dto;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* (SysRole)实体类Dto
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
@ApiModel
public class SysRoleDto extends BaseQueryDto implements Serializable {
private static final long serialVersionUID = -85366036881107510L;
@Schema(description ="角色ID")
private Long roleId;
@Schema(description ="角色编码")
private String roleCode;
@Schema(description ="角色名称")
private String roleName;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@Schema(description ="备注")
private String remark;
@Schema(description ="删除标记")
private String deleteFlag;
}

View File

@ -0,0 +1,58 @@
package com.kexue.skills.entity.dto;
import java.util.Date;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* (SysUser)实体类Dto
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
@ApiModel
public class SysUserDto extends BaseQueryDto implements Serializable {
private static final long serialVersionUID = -60817463837641372L;
@Schema(description ="主键ID")
private Long userId;
@Schema(description ="用户登录名称")
private String userName;
@Schema(description ="密码(非明文)")
private String pwd;
@Schema(description ="真实姓名")
private String realName;
@Schema(description ="手机")
private String tel;
@Schema(description ="邮箱")
private String email;
@Schema(description ="加点盐(登录时候要用到的随机数)")
private String salt;
@Schema(description ="备注")
private String remark;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@Schema(description ="创建时间")
private Date createTime;
@Schema(description ="是否启用1启用2禁用")
private Integer enable;
@Schema(description ="是否删除 0 未删除1已删除")
private Integer deleteFlag;
}

View File

@ -0,0 +1,29 @@
package com.kexue.skills.entity.dto;
import java.io.Serializable;
import com.kexue.skills.entity.base.BaseQueryDto;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
/**
* (SysUserRole)实体类Dto
*
* @author 王志维
* @since 2025-02-21 23:01:48
*/
@Data
@ApiModel
public class SysUserRoleDto extends BaseQueryDto implements Serializable {
private static final long serialVersionUID = -74751357369011844L;
@Schema(description ="角色ID")
private Long roleId;
@Schema(description ="用户ID")
private Long userId;
}

Some files were not shown because too many files have changed in this diff Show More