diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/.idea/misc.xml b/.idea/misc.xml index a8fc129..7496a8d 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,5 +8,5 @@ - + \ No newline at end of file diff --git a/pom.xml b/pom.xml index e21284b..a5d3e78 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.0 + 3.0.4 @@ -19,7 +19,7 @@ 17 - 1.9.3 + 1.11.0 @@ -39,18 +39,22 @@ com.mybatis-flex - mybatis-flex-spring-boot-starter + mybatis-flex-spring-boot3-starter ${mybatis-flex.version} - + + com.mybatis-flex mybatis-flex-processor - ${mybatis-flex.version} + 1.11.0 provided - + + com.zaxxer + HikariCP + org.springframework.boot @@ -94,6 +98,16 @@ org.springframework.boot spring-boot-starter-mail + + org.springframework + spring-tx + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.5.0 + diff --git a/src/main/java/com/yundage/chat/ChatApplication.java b/src/main/java/com/yundage/chat/ChatApplication.java index b0f5376..984166b 100644 --- a/src/main/java/com/yundage/chat/ChatApplication.java +++ b/src/main/java/com/yundage/chat/ChatApplication.java @@ -6,6 +6,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; @SpringBootApplication(exclude = {HibernateJpaAutoConfiguration.class}) + @MapperScan("com.yundage.chat.mapper") public class ChatApplication { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 201a5d1..191656a 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -24,8 +24,8 @@ mybatis-flex: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # Mapper XML location (optional) - mapper-locations: classpath*:mapper/*.xml + mapper-locations: classpath*:mapper/*.xml # JWT configuration jwt: secret: mySecretKeyForJWTTokenGenerationAndValidation @@ -43,4 +43,6 @@ server: logging: level: com.yundage.chat: debug - com.mybatisflex: debug \ No newline at end of file + com.mybatisflex: debug +# org.springframework: DEBUG +#debug: true \ No newline at end of file diff --git a/src/main/resources/mapper/PasswordResetTokenMapper.xml b/src/main/resources/mapper/PasswordResetTokenMapper.xml new file mode 100644 index 0000000..5f3790b --- /dev/null +++ b/src/main/resources/mapper/PasswordResetTokenMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/UserMapper.xml b/src/main/resources/mapper/UserMapper.xml new file mode 100644 index 0000000..6b41dd3 --- /dev/null +++ b/src/main/resources/mapper/UserMapper.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/target/classes/application.yml b/target/classes/application.yml deleted file mode 100644 index 201a5d1..0000000 --- a/target/classes/application.yml +++ /dev/null @@ -1,46 +0,0 @@ -spring: - datasource: - driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://101.200.154.78:3306/yunda_qa?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai - username: root - password: mysql_Jt3yzh - - # Mail configuration - mail: - host: smtp.gmail.com - port: 587 - username: your-email@gmail.com - password: your-app-password - properties: - mail: - smtp: - auth: true - starttls: - enable: true - -# MyBatis-Flex configuration -mybatis-flex: - # Enable SQL logging - configuration: - log-impl: org.apache.ibatis.logging.stdout.StdOutImpl - # Mapper XML location (optional) - mapper-locations: classpath*:mapper/*.xml - -# JWT configuration -jwt: - secret: mySecretKeyForJWTTokenGenerationAndValidation - expiration: 86400000 # 24 hours in milliseconds - -# App configuration -app: - reset-password-url: http://localhost:3000/reset-password - -# Server configuration -server: - port: 8080 - -# Logging configuration -logging: - level: - com.yundage.chat: debug - com.mybatisflex: debug \ No newline at end of file diff --git a/target/classes/schema.sql b/target/classes/schema.sql deleted file mode 100644 index f2bd854..0000000 --- a/target/classes/schema.sql +++ /dev/null @@ -1,113 +0,0 @@ --- Create database -CREATE DATABASE IF NOT EXISTS chat CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - -USE chat; - --- 1. 用户主表 -CREATE TABLE users ( - id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, - username VARCHAR(50) DEFAULT NULL COMMENT '昵称/展示名', - password_hash VARCHAR(255) DEFAULT NULL COMMENT '哈希密码(可为空)', - phone VARCHAR(20) UNIQUE DEFAULT NULL COMMENT '手机号', - email VARCHAR(100)UNIQUE DEFAULT NULL COMMENT '邮箱', - avatar_url VARCHAR(255) DEFAULT NULL, - user_type ENUM('personal','enterprise','admin') - NOT NULL DEFAULT 'personal' COMMENT '用户类型', - membership_level_id SMALLINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '付费等级', - status TINYINT NOT NULL DEFAULT 1 COMMENT '1=正常, 0=封禁', - created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - last_login_at DATETIME NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户主表'; - --- 2. 第三方账号绑定表 -CREATE TABLE user_auth_accounts ( - id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, - user_id BIGINT UNSIGNED NOT NULL, - provider ENUM('wechat_mini','wechat_open','google','github','apple','custom') - NOT NULL COMMENT '登录方式', - provider_user_id VARCHAR(100) NOT NULL COMMENT '第三方平台唯一ID', - access_token VARCHAR(255) DEFAULT NULL, - refresh_token VARCHAR(255) DEFAULT NULL, - expires_at DATETIME DEFAULT NULL, - created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - UNIQUE KEY uq_provider_user (provider, provider_user_id), - CONSTRAINT fk_auth_user FOREIGN KEY (user_id) REFERENCES users(id) - ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='第三方登录账号绑定表'; - --- 3. 会员等级表 -CREATE TABLE membership_levels ( - id SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, - name VARCHAR(50) NOT NULL, - price_month DECIMAL(10,2) NOT NULL DEFAULT 0.00 COMMENT '月费', - daily_msg_limit INT UNSIGNED NOT NULL DEFAULT 20, - features JSON DEFAULT NULL COMMENT '权限 JSON', - sort_order TINYINT NOT NULL DEFAULT 0, - created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员等级定义'; - --- 4. 会话表(支持普通与研究模式) -CREATE TABLE conversations ( - id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, - user_id BIGINT UNSIGNED NOT NULL, - title VARCHAR(100) DEFAULT NULL, - model_version VARCHAR(50) DEFAULT NULL COMMENT '使用模型版本', - chat_mode ENUM('chat','research') - NOT NULL DEFAULT 'chat' COMMENT 'chat=普通,research=深度研究', - is_active TINYINT NOT NULL DEFAULT 1, - created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - CONSTRAINT fk_conv_user FOREIGN KEY (user_id) REFERENCES users(id) - ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会话表'; - --- 5. 深度研究扩展表 -CREATE TABLE conversation_research_meta ( - conversation_id BIGINT UNSIGNED PRIMARY KEY, - topic VARCHAR(200) NOT NULL COMMENT '研究主题', - goal TEXT DEFAULT NULL COMMENT '研究目标描述', - progress_json JSON DEFAULT NULL COMMENT '阶段进度', - draft_report_id BIGINT UNSIGNED DEFAULT NULL COMMENT '草稿报告 ID(预留)', - cite_style ENUM('APA','IEEE','GB/T-7714') DEFAULT 'APA', - tokens_consumed INT UNSIGNED NOT NULL DEFAULT 0, - last_summary_at DATETIME DEFAULT NULL, - created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - CONSTRAINT fk_research_conv FOREIGN KEY (conversation_id) - REFERENCES conversations(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='深度研究元数据'; - --- 6. 消息表 -CREATE TABLE messages ( - id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, - conversation_id BIGINT UNSIGNED NOT NULL, - sequence_no INT UNSIGNED NOT NULL COMMENT '会话内顺序编号', - role ENUM('user','assistant','system','tool') - NOT NULL, - content LONGTEXT NOT NULL, - tokens INT UNSIGNED DEFAULT NULL, - latency_ms INT UNSIGNED DEFAULT NULL COMMENT '响应耗时', - created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_msg_conv FOREIGN KEY (conversation_id) REFERENCES conversations(id) - ON DELETE CASCADE, - UNIQUE KEY uq_conv_seq (conversation_id, sequence_no) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='消息表'; - --- 7. 密码重置令牌表(用于密码重置功能) -CREATE TABLE password_reset_tokens ( - id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, - user_id BIGINT UNSIGNED NOT NULL, - token VARCHAR(255) NOT NULL UNIQUE, - expires_at DATETIME NOT NULL, - used TINYINT NOT NULL DEFAULT 0, - created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - CONSTRAINT fk_reset_user FOREIGN KEY (user_id) REFERENCES users(id) - ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='密码重置令牌表'; - --- 插入默认会员等级数据 -INSERT INTO membership_levels (id, name, price_month, daily_msg_limit, features, sort_order) VALUES -(1, '免费版', 0.00, 20, '{"models": ["gpt-3.5"], "features": ["basic_chat"]}', 1), -(2, '专业版', 29.99, 100, '{"models": ["gpt-3.5", "gpt-4"], "features": ["basic_chat", "research_mode"]}', 2), -(3, '企业版', 99.99, 1000, '{"models": ["gpt-3.5", "gpt-4", "gpt-4-turbo"], "features": ["basic_chat", "research_mode", "priority_support"]}', 3); \ No newline at end of file diff --git a/target/generated-sources/annotations/com/yundage/chat/entity/table/PasswordResetTokenTableDef.java b/target/generated-sources/annotations/com/yundage/chat/entity/table/PasswordResetTokenTableDef.java deleted file mode 100644 index 9d6754e..0000000 --- a/target/generated-sources/annotations/com/yundage/chat/entity/table/PasswordResetTokenTableDef.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.yundage.chat.entity.table; - -import com.mybatisflex.core.query.QueryColumn; -import com.mybatisflex.core.table.TableDef; - -// Auto generate by mybatis-flex, do not modify it. -public class PasswordResetTokenTableDef extends TableDef { - - public static final PasswordResetTokenTableDef PASSWORD_RESET_TOKEN = new PasswordResetTokenTableDef(); - - public final QueryColumn ID = new QueryColumn(this, "id"); - - public final QueryColumn USED = new QueryColumn(this, "used"); - - public final QueryColumn TOKEN = new QueryColumn(this, "token"); - - public final QueryColumn USER_ID = new QueryColumn(this, "user_id"); - - public final QueryColumn CREATED_AT = new QueryColumn(this, "created_at"); - - public final QueryColumn EXPIRES_AT = new QueryColumn(this, "expires_at"); - - /** - * 所有字段。 - */ - public final QueryColumn ALL_COLUMNS = new QueryColumn(this, "*"); - - /** - * 默认字段,不包含逻辑删除或者 large 等字段。 - */ - public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, USED, TOKEN, USER_ID, CREATED_AT, EXPIRES_AT}; - - public PasswordResetTokenTableDef() { - super("", "password_reset_tokens"); - } - - private PasswordResetTokenTableDef(String schema, String name, String alisa) { - super(schema, name, alisa); - } - - public PasswordResetTokenTableDef as(String alias) { - String key = getNameWithSchema() + "." + alias; - return getCache(key, k -> new PasswordResetTokenTableDef("", "password_reset_tokens", alias)); - } - -} diff --git a/target/generated-sources/annotations/com/yundage/chat/entity/table/UserTableDef.java b/target/generated-sources/annotations/com/yundage/chat/entity/table/UserTableDef.java deleted file mode 100644 index a2b1855..0000000 --- a/target/generated-sources/annotations/com/yundage/chat/entity/table/UserTableDef.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.yundage.chat.entity.table; - -import com.mybatisflex.core.query.QueryColumn; -import com.mybatisflex.core.table.TableDef; - -// Auto generate by mybatis-flex, do not modify it. -public class UserTableDef extends TableDef { - - public static final UserTableDef USER = new UserTableDef(); - - public final QueryColumn ID = new QueryColumn(this, "id"); - - public final QueryColumn EMAIL = new QueryColumn(this, "email"); - - public final QueryColumn PHONE = new QueryColumn(this, "phone"); - - public final QueryColumn STATUS = new QueryColumn(this, "status"); - - public final QueryColumn USER_TYPE = new QueryColumn(this, "user_type"); - - public final QueryColumn USERNAME = new QueryColumn(this, "username"); - - public final QueryColumn AVATAR_URL = new QueryColumn(this, "avatar_url"); - - public final QueryColumn CREATED_AT = new QueryColumn(this, "created_at"); - - public final QueryColumn UPDATED_AT = new QueryColumn(this, "updated_at"); - - public final QueryColumn LAST_LOGIN_AT = new QueryColumn(this, "last_login_at"); - - public final QueryColumn PASSWORD_HASH = new QueryColumn(this, "password_hash"); - - public final QueryColumn MEMBERSHIP_LEVEL_ID = new QueryColumn(this, "membership_level_id"); - - /** - * 所有字段。 - */ - public final QueryColumn ALL_COLUMNS = new QueryColumn(this, "*"); - - /** - * 默认字段,不包含逻辑删除或者 large 等字段。 - */ - public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, EMAIL, PHONE, STATUS, USER_TYPE, USERNAME, AVATAR_URL, CREATED_AT, UPDATED_AT, LAST_LOGIN_AT, PASSWORD_HASH, MEMBERSHIP_LEVEL_ID}; - - public UserTableDef() { - super("", "users"); - } - - private UserTableDef(String schema, String name, String alisa) { - super(schema, name, alisa); - } - - public UserTableDef as(String alias) { - String key = getNameWithSchema() + "." + alias; - return getCache(key, k -> new UserTableDef("", "users", alias)); - } - -}