新增所有功能后端实现_yhf6/3

hot-fix
heiferleaf 2 months ago
parent de19873c67
commit 16dccb1f00

@ -1,106 +1,425 @@
# 微信小程序登录Demo后端
## 项目介绍
本项目是一个微信小程序登录的后端Demo实现了微信小程序登录、获取用户信息等功能。
## 技术栈
- Spring Boot 3.0.12
- MyBatis 3.0.1
- MySQL 8.0
- JWT
## 项目结构
```
src/main/java/com/learning/newdemo
├── config // 配置类
├── controller // 控制器
├── entity // 实体类
├── mapper // 数据访问层
├── service // 服务层
│ └── impl // 服务实现
├── util // 工具类
└── common // 通用类
```
## 运行环境
- JDK 17+
- MySQL 8.0+
- Maven 3.6+
## 数据库配置
1. 创建数据库和表
```sql
# 执行src/main/resources/db/wx_miniapp.sql脚本
```
2. 修改数据库连接信息(`application.yml`
```yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/wx_miniapp?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: 1234
```
## 微信小程序配置
修改`application.yml`中的微信小程序配置:
```yaml
wechat:
miniapp:
appid: 你的小程序APPID
secret: 你的小程序SECRET
```
## 启动项目
```bash
mvn spring-boot:run
```
## 接口说明
### 1. 登录接口
- URL: `/api/wx/login`
- Method: POST
- Body:
```json
{
"code": "微信临时登录凭证"
}
```
- Response:
```json
{
"success": true,
"code": 200,
"message": "操作成功",
"data": {
"token": "JWT令牌"
}
}
```
### 2. 获取用户信息接口
- URL: `/api/wx/user`
- Method: GET
- Headers:
```
Authorization: 登录接口返回的token
```
- Response:
```json
{
"success": true,
"code": 200,
"message": "操作成功",
"data": {
"id": 1,
"openid": "用户openid",
"nickname": "用户昵称",
"avatarUrl": "头像URL",
"gender": 1,
"country": "国家",
"province": "省份",
"city": "城市",
"language": "语言"
}
}
```
# 微信小程序辩论助手后端
## 项目介绍
本项目是一个微信小程序辩论助手的后端服务实现了微信小程序登录、获取用户信息、AI辅助立论、复盘分析、模拟辩论等功能并支持历史记录的保存与查询。
## 技术栈
- Spring Boot 3.0.12
- MyBatis 3.0.1
- MySQL 8.0
- JWT
- RestTemplate (AI接口调用)
## 项目结构
```
src/main/java/com/learning/newdemo
├── config // 配置类
├── controller // 控制器
├── entity // 实体类
├── mapper // 数据访问层
├── service // 服务层
│ └── impl // 服务实现
├── util // 工具类
└── common // 通用类
```
## 运行环境
- JDK 17+
- MySQL 8.0+
- Maven 3.6+
## 数据库配置
1. 创建数据库和表
```sql
# 执行src/main/resources/db/wx_miniapp.sql脚本
# 用户表
CREATE TABLE `wx_user` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`openid` varchar(100) NOT NULL COMMENT '微信openid',
`nickname` varchar(50) DEFAULT NULL COMMENT '昵称',
`avatar_url` varchar(255) DEFAULT NULL COMMENT '头像',
`gender` tinyint DEFAULT NULL COMMENT '性别 0-未知 1-男 2-女',
`country` varchar(50) DEFAULT NULL COMMENT '国家',
`province` varchar(50) DEFAULT NULL COMMENT '省份',
`city` varchar(50) DEFAULT NULL COMMENT '城市',
`language` varchar(50) DEFAULT NULL COMMENT '语言',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_openid` (`openid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微信用户表';
# 对话活动表
CREATE TABLE `wx_conversation` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`user_id` bigint NOT NULL COMMENT '用户ID',
`type` varchar(20) NOT NULL COMMENT '对话类型(debate/argument/review)',
`title` varchar(255) DEFAULT NULL COMMENT '对话标题',
`preview` varchar(255) DEFAULT NULL COMMENT '预览内容(最后一次AI回复的前10个字符)',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='对话活动表';
# 辩论历史记录表
CREATE TABLE `wx_debate_record` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`conversation_id` bigint NOT NULL COMMENT '对话活动ID',
`content` text COMMENT 'AI回复内容',
`user_message` text COMMENT '用户消息',
`sequence` int NOT NULL COMMENT '消息序号',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_conversation_id` (`conversation_id`),
KEY `idx_sequence` (`sequence`),
CONSTRAINT `fk_debate_conversation` FOREIGN KEY (`conversation_id`) REFERENCES `wx_conversation` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='辩论历史记录表';
# 立论历史记录表
CREATE TABLE `wx_argument_record` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`conversation_id` bigint NOT NULL COMMENT '对话活动ID',
`topic` varchar(255) DEFAULT NULL COMMENT '辩题',
`stance` varchar(50) DEFAULT NULL COMMENT '立场',
`content` text COMMENT 'AI回复内容',
`user_message` text COMMENT '用户消息',
`sequence` int NOT NULL COMMENT '消息序号',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_conversation_id` (`conversation_id`),
KEY `idx_sequence` (`sequence`),
CONSTRAINT `fk_argument_conversation` FOREIGN KEY (`conversation_id`) REFERENCES `wx_conversation` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='立论历史记录表';
# 复盘历史记录表
CREATE TABLE `wx_review_record` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`conversation_id` bigint NOT NULL COMMENT '对话活动ID',
`content` text COMMENT 'AI回复内容',
`user_message` text COMMENT '用户消息',
`sequence` int NOT NULL COMMENT '消息序号',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_conversation_id` (`conversation_id`),
KEY `idx_sequence` (`sequence`),
CONSTRAINT `fk_review_conversation` FOREIGN KEY (`conversation_id`) REFERENCES `wx_conversation` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='复盘历史记录表';
```
2. 修改数据库连接信息(`application.yml`
```yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/wx_miniapp?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: 1234
```
## 微信小程序配置
修改`application.yml`中的微信小程序配置:
```yaml
wechat:
miniapp:
appid: 你的小程序APPID
secret: 你的小程序SECRET
```
## AI接口配置
修改`application.yml`中的AI接口配置
```yaml
ai:
api:
url: AI接口地址
key: API密钥(如果需要)
```
## 启动项目
```bash
mvn spring-boot:run
```
## 接口说明
### 1. 登录接口
- URL: `/api/wx/login`
- Method: POST
- Body:
```json
{
"code": "微信临时登录凭证"
}
```
- Response:
```json
{
"success": true,
"code": 200,
"message": "操作成功",
"data": {
"token": "JWT令牌"
}
}
```
### 2. 获取用户信息接口
- URL: `/api/wx/user`
- Method: GET
- Headers:
```
Authorization: 登录接口返回的token
```
- Response:
```json
{
"success": true,
"code": 200,
"message": "操作成功",
"data": {
"id": 1,
"openid": "用户openid",
"nickname": "用户昵称",
"avatarUrl": "头像URL",
"gender": 1,
"country": "国家",
"province": "省份",
"city": "城市",
"language": "语言"
}
}
```
### 3. AI接口
#### 3.1 立论接口
- URL: `/api/ai/argument`
- Method: POST
- Headers:
```
Authorization: 登录接口返回的token
```
- Body:
```json
{
"conversationId": "对话活动ID(可选,有则更新,无则新建)",
"topic": "辩题",
"stance": "立场(正方/反方)"
}
```
- Response:
```json
{
"success": true,
"code": 200,
"message": "操作成功",
"data": {
"content": "AI生成的立论内容",
"conversationId": "对话活动ID"
}
}
```
- 调用时机:用户在立论助手页面输入辩题和选择立场后,点击发送按钮时调用
- 数据库操作:
- 如果没有conversationId则在wx_conversation表中新建一条记录type为"argument"并返回新建的conversationId
- 在wx_argument_record表中插入一条记录包含用户消息和AI回复内容
- 更新wx_conversation表中对应记录的preview字段(取AI回复内容前10个字符)
#### 3.2 复盘接口
- URL: `/api/ai/review`
- Method: POST
- Headers:
```
Authorization: 登录接口返回的token
```
- Body:
```json
{
"conversationId": "对话活动ID(可选,有则更新,无则新建)",
"content": "用户输入的辩论内容或复盘需求"
}
```
- Response:
```json
{
"success": true,
"code": 200,
"message": "操作成功",
"data": {
"content": "AI生成的复盘分析内容",
"conversationId": "对话活动ID"
}
}
```
- 调用时机:用户在复盘分析页面输入辩论内容或复盘需求后,点击发送按钮时调用
- 数据库操作:
- 如果没有conversationId则在wx_conversation表中新建一条记录type为"review"并返回新建的conversationId
- 在wx_review_record表中插入一条记录包含用户消息和AI回复内容
- 更新wx_conversation表中对应记录的preview字段(取AI回复内容前10个字符)
#### 3.3 辩论接口
- URL: `/api/ai/debate`
- Method: POST
- Headers:
```
Authorization: 登录接口返回的token
```
- Body:
```json
{
"conversationId": "对话活动ID(可选,有则更新,无则新建)",
"userMessage": "用户当前输入的消息"
}
```
- Response:
```json
{
"success": true,
"code": 200,
"message": "操作成功",
"data": {
"content": "AI生成的辩论回复内容",
"conversationId": "对话活动ID"
}
}
```
- 调用时机:用户在模拟辩论页面输入消息后,点击发送按钮时调用
- 数据库操作:
- 如果没有conversationId则在wx_conversation表中新建一条记录type为"debate"并返回新建的conversationId
- 在wx_debate_record表中插入一条记录包含用户消息和AI回复内容
- 更新wx_conversation表中对应记录的preview字段(取AI回复内容前10个字符)
### 4. 历史记录接口
#### 4.1 获取对话活动列表
- URL: `/api/conversation/list`
- Method: GET
- Headers:
```
Authorization: 登录接口返回的token
```
- Response:
```json
{
"success": true,
"code": 200,
"message": "操作成功",
"data": [
{
"id": 1,
"type": "debate",
"title": "对话标题",
"preview": "AI回复的前10个字符",
"createTime": "2023-01-01 12:00:00"
}
]
}
```
- 调用时机用户进入历史记录列表页面时调用根据当前所在模块传入不同的type参数
- 数据库操作查询当前用户在wx_conversation表中指定type的所有记录按创建时间倒序排列
#### 4.2 获取辩论历史记录详情
- URL: `/api/conversation/debate/{conversationId}`
- Method: GET
- Headers:
```
Authorization: 登录接口返回的token
```
- Response:
```json
{
"success": true,
"code": 200,
"message": "操作成功",
"data": {
"conversation": {
"id": 1,
"type": "debate",
"title": "对话标题",
"createTime": "2023-01-01 12:00:00"
},
"records": [
{
"id": 1,
"userMessage": "用户消息",
"content": "AI回复内容",
"sequence": 1,
"createTime": "2023-01-01 12:00:00"
}
]
}
}
```
- 调用时机:用户点击辩论历史记录列表中的某一项时调用
- 数据库操作:
- 查询wx_conversation表中指定id的记录
- 查询wx_debate_record表中conversation_id等于指定id的所有记录按sequence排序
#### 4.3 获取立论历史记录详情
- URL: `/api/conversation/argument/{conversationId}`
- Method: GET
- Headers:
```
Authorization: 登录接口返回的token
```
- Response:
```json
{
"success": true,
"code": 200,
"message": "操作成功",
"data": {
[
{
"id": 1,
"userMessage": "用户消息",
"content": "AI回复内容",
"sequence": 1,
"createTime": "2023-01-01 12:00:00"
}
]
}
}
```
- 调用时机:用户点击立论历史记录列表中的某一项时调用
- 数据库操作:
- 查询wx_conversation表中指定id的记录
- 查询wx_argument_record表中conversation_id等于指定id的所有记录按sequence排序
#### 4.4 获取复盘历史记录详情
- URL: `/api/conversation/review/{conversationId}`
- Method: GET
- Headers:
```
Authorization: 登录接口返回的token
```
- Response:
```json
{
"success": true,
"code": 200,
"message": "操作成功",
"data": {
[
{
"id": 1,
"userMessage": "用户消息",
"content": "AI回复内容",
"sequence": 1,
"createTime": "2023-01-01 12:00:00"
}
]
}
}
```
- 调用时机:用户点击复盘历史记录列表中的某一项时调用
- 数据库操作:
- 查询wx_conversation表中指定id的记录
- 查询wx_review_record表中conversation_id等于指定id的所有记录按sequence排序

@ -0,0 +1,23 @@
package com.learning.newdemo.Dto;
import com.learning.newdemo.entity.WxArgument;
import lombok.Data;
import java.util.Date;
@Data
public class ArgumentDetailDTO {
private Integer id;
private String userMessage;
private String content;
private Integer sequence;
private Date createTime;
public ArgumentDetailDTO(WxArgument wxArgument) {
this.id = wxArgument.getId();
this.userMessage = wxArgument.getUserMessage();
this.content = wxArgument.getContent();
this.sequence = wxArgument.getSequence();
this.createTime = wxArgument.getCreateTime();
}
}

@ -0,0 +1,23 @@
package com.learning.newdemo.Dto;
import com.learning.newdemo.entity.WxConversation;
import lombok.Data;
import java.util.Date;
@Data
public class ConversationDTO {
private Long id;
private String type; // "debate"/"argument"/"review"
private String title;
private String preview; // AI回复的前10个字符
private Date updateTime;
public ConversationDTO(WxConversation wxConversation) {
this.id = wxConversation.getId();
this.type = wxConversation.getType();
this.title = wxConversation.getTitle();
this.preview = wxConversation.getPreview();
this.updateTime = wxConversation.getUpdateTime();
}
}

@ -0,0 +1,23 @@
package com.learning.newdemo.Dto;
import com.learning.newdemo.entity.WxDebate;
import lombok.Data;
import java.util.Date;
@Data
public class DebateDetailDTO {
private Long id;
private String userMessage;
private String content;
private Integer sequence;
private Date createTime;
public DebateDetailDTO(WxDebate wxDebate) {
this.id = wxDebate.getId();
this.userMessage = wxDebate.getUserMessage();
this.content = wxDebate.getContent();
this.sequence = wxDebate.getSequence();
this.createTime = wxDebate.getCreateTime();
}
}

@ -0,0 +1,23 @@
package com.learning.newdemo.Dto;
import com.learning.newdemo.entity.WxReview;
import lombok.Data;
import java.util.Date;
@Data
public class ReviewDetailDTO {
private Long id;
private String userMessage; // 用户消息
private String content; // AI回复内容
private Integer sequence; // 消息序号
private Date createTime;
public ReviewDetailDTO(WxReview wxReview) {
this.id = wxReview.getId();
this.userMessage = wxReview.getUserMessage();
this.content = wxReview.getContent();
this.sequence = wxReview.getSequence();
this.createTime = wxReview.getCreateTime();
}
}

@ -7,10 +7,7 @@ import com.learning.newdemo.service.WxDebateService;
import com.learning.newdemo.service.WxReviewService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@ -34,11 +31,13 @@ public class WxAIController {
private String content;
private Long conversationId;
@PostMapping("/argument")
public Result<Map<String, Object>> getArgument(@RequestBody Map<String, String> params){
public Result<Map<String, Object>> getArgument(@RequestHeader ("Authorization") String token, @RequestBody Map<String, String> params){
topic = params.get("topic");
stance = params.get("stance");
conversationId = Long.parseLong(params.get("conversationId"));
if(topic == null || stance == null){
return Result.error("立论主题或者内容为空");
@ -52,8 +51,11 @@ public class WxAIController {
return Result.error("立论获取失败");
}
long relatedConversationId = wxArgumentService.UpdateArgument(conversationId, topic, stance, argument, topic + stance, token);
Map<String, Object> data = new HashMap<>();
data.put("argument", argument);
data.put("content", argument);
data.put("conversationId", relatedConversationId);
// 查看data
log.info("立论获取成功:{}", argument);
@ -65,10 +67,11 @@ public class WxAIController {
}
@PostMapping("/review")
public Result<Map<String, Object>> review(@RequestBody Map<String, String> params){
public Result<Map<String, Object>> review(@RequestHeader ("Authorization") String token,@RequestBody Map<String, String> params){
log.info("请求内容: {}", params);
content = params.get("content");
conversationId = Long.parseLong(params.get("conversationId"));
try {
String review = wxReviewService.GetReview(content);
@ -76,8 +79,11 @@ public class WxAIController {
return Result.error("复盘获取失败");
}
long relatedConversationId = wxReviewService.UpdateReview(conversationId, review, content, token);
Map<String, Object> data = new HashMap<>();
data.put("review", review);
data.put("conversationId", relatedConversationId);
// 查看data
log.info("复盘获取成功:{}", review);
@ -88,18 +94,23 @@ public class WxAIController {
}
}
@PostMapping("/debate")
public Result<Map<String, Object>> debate(@RequestBody Map<String, String> params){
public Result<Map<String, Object>> debate(@RequestHeader ("Authorization") String token, @RequestBody Map<String, String> params){
log.info("请求内容: {}", params);
String history = params.get("history");
String userMessage = params.get("userMessage");
conversationId = Long.parseLong(params.get("conversationId"));
try {
String debate = wxDebateService.GetDebate(history, userMessage);
if (debate == null) {
return Result.error("辩论获取失败");
}
long relatedConversationId = wxDebateService.UpdateDebate(conversationId, debate, userMessage, token);
Map<String, Object> data = new HashMap<>();
data.put("debate", debate);
data.put("conversationId", relatedConversationId);
// 查看data
log.info("辩论获取成功:{}", debate);

@ -0,0 +1,103 @@
package com.learning.newdemo.controller;
import com.learning.newdemo.Dto.ArgumentDetailDTO;
import com.learning.newdemo.Dto.ConversationDTO;
import com.learning.newdemo.Dto.DebateDetailDTO;
import com.learning.newdemo.Dto.ReviewDetailDTO;
import com.learning.newdemo.common.Result;
import com.learning.newdemo.entity.WxArgument;
import com.learning.newdemo.entity.WxConversation;
import com.learning.newdemo.entity.WxDebate;
import com.learning.newdemo.entity.WxReview;
import com.learning.newdemo.mapper.WxArgumentMapper;
import com.learning.newdemo.mapper.WxConversationMapper;
import com.learning.newdemo.mapper.WxDebateMapper;
import com.learning.newdemo.mapper.WxReviewMapper;
import com.learning.newdemo.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@RestController
@RequestMapping("api/conversation")
public class WxConversationController {
private final WxConversationMapper wxConversationMapper;
private final WxDebateMapper wxDebateMapper;
private final WxArgumentMapper wxArgumentMapper;
private final WxReviewMapper wxReviewMapper;
private final JwtUtil jwtUtil;
public WxConversationController(WxConversationMapper wxConversationMapper, WxDebateMapper wxDebateMapper, WxArgumentMapper wxArgumentMapper, WxReviewMapper wxReviewMapper, JwtUtil jwtUtil) {
this.wxConversationMapper = wxConversationMapper;
this.wxDebateMapper = wxDebateMapper;
this.wxArgumentMapper = wxArgumentMapper;
this.wxReviewMapper = wxReviewMapper;
this.jwtUtil = jwtUtil;
}
@GetMapping("/list")
public Result<List<ConversationDTO>> getConversationList(@RequestHeader("Authorization") String token){
try{
int userId = jwtUtil.getUserIdFromToken(token);
List<WxConversation> conversations = wxConversationMapper.selectByUserId(userId);
List<ConversationDTO> result = conversations.stream()
.map(conv -> new ConversationDTO(
conv))
.collect(Collectors.toList());
return Result.success(result);
} catch (Exception e){
log.error("获取对话失败");
return Result.error("获取对话失败:" + e.getMessage());
}
}
@GetMapping( "/debate/{conversation}")
public Result<List<DebateDetailDTO>> getDebate(@PathVariable("conversation") Long conversationId) {
try{
List<WxDebate> wxDebates = wxDebateMapper.selectByConversationId(conversationId);
List<DebateDetailDTO> debateDetailDTOS = wxDebates.stream().map(DebateDetailDTO::new).collect(Collectors.toList());
return Result.success(debateDetailDTOS);
} catch (Exception e) {
log.error("获取辩论失败", e);
return Result.error("获取辩论失败:" + e.getMessage());
}
}
@GetMapping("/argument/{conversationId}")
public Result<List<ArgumentDetailDTO>> getArgument(@PathVariable Long conversationId) {
try {
List <WxArgument> wxArguments = wxArgumentMapper.selectByConversationId(conversationId);
List <ArgumentDetailDTO> argumentDetailDTOS = wxArguments.stream().map(ArgumentDetailDTO::new).collect(Collectors.toList());
return Result.success(argumentDetailDTOS);
} catch ( Exception e) {
log.error("获取立论失败", e);
return Result.error("获取立论失败:" + e.getMessage());
}
}
@GetMapping("/review/{conversationId}")
public Result<List<ReviewDetailDTO>> getReview(@PathVariable Long conversationId) {
try {
List<WxReview> wxReviews = wxReviewMapper.selectByConversationId(conversationId);
List<ReviewDetailDTO> reviewDetailDTOS = wxReviews.stream().map(ReviewDetailDTO::new).collect(Collectors.toList());
return Result.success(reviewDetailDTOS);
} catch ( Exception e){
log.error("获取评论失败", e);
return Result.error("获取评论失败:" + e.getMessage());
}
}
}

@ -0,0 +1,25 @@
package com.learning.newdemo.entity;
import lombok.Data;
import java.util.Date;
@Data
public class WxArgument {
// 主键
private Integer id;
// 对话活动Id外键
private long conversationId;
// 辩题
private String topic;
// 立场
private String stance;
// AI回复内容
private String content;
// 用户信息
private String userMessage;
// 消息序号
private Integer sequence;
// 创建时间
private Date createTime;
}

@ -0,0 +1,16 @@
package com.learning.newdemo.entity;
import lombok.Data;
import java.util.Date;
@Data
public class WxConversation {
private Long id;
private int userId;
private String type;
private String title;
private String preview;
private Date createTime;
private Date updateTime;
}

@ -0,0 +1,15 @@
package com.learning.newdemo.entity;
import lombok.Data;
import java.util.Date;
@Data
public class WxDebate {
private Long id;
private Long conversationId;
private String content;
private String userMessage;
private Integer sequence;
private Date createTime;
}

@ -0,0 +1,15 @@
package com.learning.newdemo.entity;
import lombok.Data;
import java.util.Date;
@Data
public class WxReview {
private Long id;
private Long conversationId; // 关联的对话活动ID
private String content; // AI回复内容
private String userMessage; // 用户消息
private Integer sequence; // 消息序号
private Date createTime;
}

@ -0,0 +1,12 @@
package com.learning.newdemo.mapper;
import com.learning.newdemo.entity.WxArgument;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface WxArgumentMapper {
List<WxArgument> selectByConversationId(long conversationId);
int insert(WxArgument wxArgument);
}

@ -0,0 +1,13 @@
package com.learning.newdemo.mapper;
import com.learning.newdemo.entity.WxConversation;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface WxConversationMapper {
List<WxConversation> selectByUserId(Integer userId);
int insert(WxConversation wxConversation);
int updatePreview(Long conversationId, String preview);
}

@ -0,0 +1,12 @@
package com.learning.newdemo.mapper;
import com.learning.newdemo.entity.WxDebate;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface WxDebateMapper {
List<WxDebate> selectByConversationId(Long conversationId);
int insert(WxDebate wxDebate);
}

@ -0,0 +1,12 @@
package com.learning.newdemo.mapper;
import com.learning.newdemo.entity.WxReview;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface WxReviewMapper {
List<WxReview> selectByConversationId(Long conversationId);
int insert(WxReview wxReview);
}

@ -6,4 +6,5 @@ package com.learning.newdemo.service;
public interface WxArgumentService {
String GetArgument(String topic, String stance);
long UpdateArgument(Long conversationId, String topic, String stance, String content, String userMessage, String token);
}

@ -2,4 +2,5 @@ package com.learning.newdemo.service;
public interface WxDebateService {
String GetDebate(String history, String userMessage);
long UpdateDebate(Long conversationId, String content, String userMessage, String token);
}

@ -2,4 +2,5 @@ package com.learning.newdemo.service;
public interface WxReviewService {
String GetReview(String content);
long UpdateReview(Long conversationId, String content, String userMessage, String token);
}

@ -1,33 +1,33 @@
package com.learning.newdemo.service;
import com.learning.newdemo.entity.WxUser;
/**
*
*/
public interface WxUserService {
/**
*
*
* @param code
* @return tokennull
*/
String login(String code);
/**
* openid
*
* @param openid
* @return
*/
WxUser getUserByOpenid(String openid);
/**
*
*
* @param wxUser
* @return
*/
boolean updateUser(WxUser wxUser);
package com.learning.newdemo.service;
import com.learning.newdemo.entity.WxUser;
/**
*
*/
public interface WxUserService {
/**
*
*
* @param code
* @return tokennull
*/
String login(String code);
/**
* openid
*
* @param openid
* @return Id
*/
int getUserByOpenid(String openid);
/**
*
*
* @param wxUser
* @return
*/
boolean updateUser(WxUser wxUser);
}

@ -1,6 +1,12 @@
package com.learning.newdemo.service.impl;
import com.learning.newdemo.entity.WxArgument;
import com.learning.newdemo.entity.WxConversation;
import com.learning.newdemo.mapper.WxArgumentMapper;
import com.learning.newdemo.mapper.WxConversationMapper;
import com.learning.newdemo.service.WxArgumentService;
import com.learning.newdemo.util.JwtUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
@ -11,11 +17,16 @@ import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Date;
@Service
@Slf4j
public class WxArgumentServiceImpl implements WxArgumentService {
private final RestTemplate restTemplate;
private final RestTemplate _restTemplate;
private final WxArgumentMapper _wxArgumentMapper;
private final WxConversationMapper _wxConversationMapper;
private final JwtUtil jwtUtil;
@Value("${ai.argument.header.Authorization}") private String authorizationHeader;
@Value("${ai.argument.body.message.role-sys}") private String roleSys;
@ -33,8 +44,11 @@ public class WxArgumentServiceImpl implements WxArgumentService {
@Value("${ai.argument.body.logprobs}") private boolean logprobs;
@Value("${ai.argument.url}") private String url;
public WxArgumentServiceImpl(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
public WxArgumentServiceImpl(RestTemplate restTemplate, WxArgumentMapper wxArgumentMapper, WxConversationMapper wxConversationMapper, JwtUtil jwtUtil) {
this._restTemplate = restTemplate;
this._wxArgumentMapper = wxArgumentMapper;
this._wxConversationMapper = wxConversationMapper;
this.jwtUtil = jwtUtil;
}
@Override
@ -75,7 +89,7 @@ public class WxArgumentServiceImpl implements WxArgumentService {
log.info("请求体:{}", requestBody);
HttpEntity<String> requestEntity = new HttpEntity<>(requestBody, headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
ResponseEntity<String> response = _restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
return response.getBody();
} catch (Exception e) {
log.error("向AI获取立论失败", e);
@ -92,4 +106,37 @@ public class WxArgumentServiceImpl implements WxArgumentService {
.replace("\r", "\\r")
.replace("\t", "\\t");
}
@Override
public long UpdateArgument(Long conversationId, String topic, String stance, String content, String userMessage, String token) {
long relatedConversationId = conversationId;
if(conversationId == -1){
int userId = jwtUtil.getUserIdFromToken(token);
WxConversation wxConversation = new WxConversation();
wxConversation.setUserId(userId);
wxConversation.setType("argument");
wxConversation.setTitle(topic);
// 渲染preview的前10个字符
wxConversation.setPreview(content.substring(0, Math.min(content.length(), 10)));
wxConversation.setCreateTime(new Date());
wxConversation.setUpdateTime(new Date());
_wxConversationMapper.insert(wxConversation);
relatedConversationId = wxConversation.getId();
}
else{
_wxConversationMapper.updatePreview(conversationId, content.substring(0, Math.min(content.length(), 10)));
}
WxArgument wxArgument = new WxArgument();
wxArgument.setConversationId(relatedConversationId);
wxArgument.setTopic(topic);
wxArgument.setStance(stance);
wxArgument.setContent(content);
wxArgument.setUserMessage(userMessage);
wxArgument.setSequence(_wxArgumentMapper.selectByConversationId(relatedConversationId).size() + 1);
wxArgument.setCreateTime(new Date());
_wxArgumentMapper.insert(wxArgument);
return relatedConversationId;
}
}

@ -1,12 +1,18 @@
package com.learning.newdemo.service.impl;
import com.learning.newdemo.entity.WxDebate;
import com.learning.newdemo.entity.WxConversation;
import com.learning.newdemo.mapper.WxConversationMapper;
import com.learning.newdemo.mapper.WxDebateMapper;
import com.learning.newdemo.service.WxDebateService;
import com.learning.newdemo.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Date;
@Service
@ -14,6 +20,9 @@ import org.springframework.web.client.RestTemplate;
public class WxDebateServiceImpl implements WxDebateService {
// 通过构造函数从IOC容器中注入RestTemplate
private final RestTemplate restTemplate;
private final WxDebateMapper wxDebateMapper;
private final WxConversationMapper wxConversationMapper;
private final JwtUtil jwtUtil;
@Value("${ai.debate.body.message.content-sys}") private String contentSys;
@Value("${ai.debate.header.Authorization}") private String authorizationHeader;
@ -31,8 +40,11 @@ public class WxDebateServiceImpl implements WxDebateService {
@Value("${ai.debate.body.logprobs}") private boolean logprobs;
@Value("${ai.debate.url}") private String url;
public WxDebateServiceImpl(RestTemplate restTemplate) {
public WxDebateServiceImpl(RestTemplate restTemplate, WxDebateMapper wxDebateMapper, WxConversationMapper wxConversationMapper, JwtUtil jwtUtil) {
this.restTemplate = restTemplate;
this.wxDebateMapper = wxDebateMapper;
this.wxConversationMapper = wxConversationMapper;
this.jwtUtil = jwtUtil;
}
@Override
@ -90,4 +102,32 @@ public class WxDebateServiceImpl implements WxDebateService {
.replace("\r", "\\r")
.replace("\t", "\\t");
}
@Override
public long UpdateDebate(Long conversationId, String content, String userMessage, String token) {
long relatedConversationId = conversationId;
if(conversationId == -1){
int userId = jwtUtil.getUserIdFromToken(token);
WxConversation wxConversation = new WxConversation();
wxConversation.setUserId(userId);
wxConversation.setType("debate");
wxConversation.setTitle("");
wxConversation.setPreview(content.substring(0, Math.min(content.length(), 10)));
wxConversation.setCreateTime(new Date());
wxConversation.setUpdateTime(new Date());
}
else{
wxConversationMapper.updatePreview(conversationId, content.substring(0, Math.min(content.length(), 10)));
}
WxDebate wxDebate = new WxDebate();
wxDebate.setConversationId(relatedConversationId);
wxDebate.setContent(content);
wxDebate.setUserMessage(userMessage);
wxDebate.setSequence(wxDebateMapper.selectByConversationId(relatedConversationId).size() + 1);
wxDebate.setCreateTime(new Date());
wxDebateMapper.insert(wxDebate);
return relatedConversationId;
}
}

@ -1,17 +1,27 @@
package com.learning.newdemo.service.impl;
import com.learning.newdemo.entity.WxReview;
import com.learning.newdemo.entity.WxConversation;
import com.learning.newdemo.mapper.WxConversationMapper;
import com.learning.newdemo.mapper.WxReviewMapper;
import com.learning.newdemo.service.WxReviewService;
import com.learning.newdemo.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.util.Date;
@Service
@Slf4j
public class WxReviewServiceImpl implements WxReviewService {
private final RestTemplate restTemplate;
private final WxReviewMapper wxReviewMapper;
private final WxConversationMapper wxConversationMapper;
private final JwtUtil jwtUtil;
@Value("${ai.argument.header.Authorization}") private String authorizationHeader;
@Value("${ai.argument.body.message.role-sys}") private String roleSys;
@ -29,8 +39,11 @@ public class WxReviewServiceImpl implements WxReviewService {
@Value("${ai.argument.body.logprobs}") private boolean logprobs;
@Value("${ai.argument.url}") private String url;
public WxReviewServiceImpl(RestTemplate restTemplate) {
public WxReviewServiceImpl(RestTemplate restTemplate, WxReviewMapper wxReviewMapper, WxConversationMapper wxConversationMapper, JwtUtil jwtUtil) {
this.restTemplate = restTemplate;
this.wxReviewMapper = wxReviewMapper;
this.wxConversationMapper = wxConversationMapper;
this.jwtUtil = jwtUtil;
}
@Override
@ -88,4 +101,31 @@ public class WxReviewServiceImpl implements WxReviewService {
.replace("\r", "\\r")
.replace("\t", "\\t");
}
@Override
public long UpdateReview(Long conversationId, String content, String userMessage, String token) {
long relatedConversationId = conversationId;
if(conversationId == -1){
int userId = jwtUtil.getUserIdFromToken(token);
WxConversation wxConversation = new WxConversation();
wxConversation.setUserId(userId);
wxConversation.setType("review");
wxConversation.setTitle("");
wxConversation.setPreview(content.substring(0, Math.min(content.length(), 10)));
wxConversation.setCreateTime(new Date());
wxConversation.setUpdateTime(new Date());
}
else{
wxConversationMapper.updatePreview(conversationId, content.substring(0, Math.min(content.length(), 10)));
}
WxReview wxReview = new WxReview();
wxReview.setConversationId(relatedConversationId);
wxReview.setContent(content);
wxReview.setUserMessage(userMessage);
wxReview.setSequence(wxReviewMapper.selectByConversationId(relatedConversationId).size() + 1);
wxReview.setCreateTime(new Date());
wxReviewMapper.insert(wxReview);
return relatedConversationId;
}
}

@ -62,10 +62,10 @@ public class WxUserServiceImpl implements WxUserService {
}
// 根据openid获取或创建用户
getUserByOpenid(openid);
int userId = getUserByOpenid(openid);
// 生成jwt token
return jwtUtil.generateToken(openid);
return jwtUtil.generateToken(userId);
} catch (Exception e) {
log.error("微信登录异常", e);
return null;
@ -73,7 +73,7 @@ public class WxUserServiceImpl implements WxUserService {
}
@Override
public WxUser getUserByOpenid(String openid) {
public int getUserByOpenid(String openid) {
WxUser wxUser = wxUserMapper.selectByOpenid(openid);
if (wxUser == null) {
// 如果用户不存在,创建新用户
@ -82,7 +82,7 @@ public class WxUserServiceImpl implements WxUserService {
wxUserMapper.insert(wxUser);
wxUser = wxUserMapper.selectByOpenid(openid);
}
return wxUser;
return wxUser.getId().intValue();
}
@Override

@ -1,112 +1,122 @@
package com.learning.newdemo.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* JWT
*/
@Component
public class JwtUtil {
/**
*
*/
@Value("${jwt.secret}")
private String secret;
/**
*
*/
@Value("${jwt.expiration}")
private Long expiration;
/**
* token
*/
public String generateToken(String openid) {
Map<String, Object> claims = new HashMap<>();
claims.put("openid", openid);
return generateToken(claims);
}
/**
* tokenopenid
*/
public String getOpenidFromToken(String token) {
String openid;
try {
Claims claims = getClaimsFromToken(token);
openid = (String) claims.get("openid");
} catch (Exception e) {
openid = null;
}
return openid;
}
/**
* token
*/
public Boolean isTokenExpired(String token) {
try {
Claims claims = getClaimsFromToken(token);
Date expiration = claims.getExpiration();
return expiration.before(new Date());
} catch (Exception e) {
return true;
}
}
/**
* tokenJWT
*/
private Claims getClaimsFromToken(String token) {
Claims claims = null;
try {
// 使用正确的方法: parseClaimsJws而不是parseClaimsJwt
claims = Jwts.parserBuilder()
.setSigningKey(getSignKey())
.build()
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
e.printStackTrace();
}
return claims;
}
/**
* token
*/
private String generateToken(Map<String, Object> claims) {
Date createdDate = new Date();
Date expirationDate = new Date(createdDate.getTime() + expiration);
JwtBuilder builder = Jwts.builder()
.setClaims(claims)
.setIssuedAt(createdDate)
.setExpiration(expirationDate)
.signWith(getSignKey(), SignatureAlgorithm.HS256);
return builder.compact();
}
/**
*
*/
private SecretKey getSignKey() {
byte[] keyBytes = Decoders.BASE64.decode(secret);
return Keys.hmacShaKeyFor(keyBytes);
}
package com.learning.newdemo.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* JWT
*/
@Component
public class JwtUtil {
/**
*
*/
@Value("${jwt.secret}")
private String secret;
/**
*
*/
@Value("${jwt.expiration}")
private Long expiration;
/**
* token
*/
public String generateToken(int userId) {
Map<String, Object> claims = new HashMap<>();
claims.put("userId", userId);
return generateToken(claims);
}
/**
* tokenopenid
*/
public int getUserIdFromToken(String bearerToken) {
int userId;
try {
String token = extractToken(bearerToken);
Claims claims = getClaimsFromToken(token);
userId = (int) claims.get("userId");
} catch (Exception e) {
userId = -1;
}
return userId;
}
/**
* token
*/
public Boolean isTokenExpired(String token) {
try {
Claims claims = getClaimsFromToken(token);
Date expiration = claims.getExpiration();
return expiration.before(new Date());
} catch (Exception e) {
return true;
}
}
/**
* tokenJWT
*/
private Claims getClaimsFromToken(String token) {
Claims claims = null;
try {
// 使用正确的方法: parseClaimsJws而不是parseClaimsJwt
claims = Jwts.parserBuilder()
.setSigningKey(getSignKey())
.build()
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
System.out.println("Token解析失败: " + e.getMessage());
}
return claims;
}
/**
* token
*/
private String generateToken(Map<String, Object> claims) {
Date createdDate = new Date();
Date expirationDate = new Date(createdDate.getTime() + expiration);
JwtBuilder builder = Jwts.builder()
.setClaims(claims)
.setIssuedAt(createdDate)
.setExpiration(expirationDate)
.signWith(getSignKey(), SignatureAlgorithm.HS256);
return builder.compact();
}
/**
*
*/
private SecretKey getSignKey() {
byte[] keyBytes = Decoders.BASE64.decode(secret);
return Keys.hmacShaKeyFor(keyBytes);
}
/**
* token
*/
public String extractToken(String bearerToken){
if(bearerToken != null && bearerToken.startsWith("Bearer "))
return bearerToken.substring(7);
return bearerToken;
}
}

@ -5,7 +5,7 @@ spring:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/wx_miniapp?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
password: 1234
mybatis:
mapper-locations: classpath:mapper/*.xml

@ -1,22 +0,0 @@
-- 创建数据库
CREATE DATABASE IF NOT EXISTS wx_miniapp DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
-- 使用数据库
USE wx_miniapp;
-- 创建微信用户表
CREATE TABLE IF NOT EXISTS `wx_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`openid` varchar(100) NOT NULL COMMENT '微信openid',
`nickname` varchar(50) DEFAULT NULL COMMENT '昵称',
`avatar_url` varchar(500) DEFAULT NULL COMMENT '头像URL',
`gender` tinyint(4) DEFAULT NULL COMMENT '性别 0-未知 1-男 2-女',
`country` varchar(50) DEFAULT NULL COMMENT '国家',
`province` varchar(50) DEFAULT NULL COMMENT '省份',
`city` varchar(50) DEFAULT NULL COMMENT '城市',
`language` varchar(50) DEFAULT NULL COMMENT '语言',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_openid` (`openid`) COMMENT 'openid唯一索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微信用户表';

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.learning.newdemo.mapper.WxArgumentMapper">
<!-- 基础结果映射 -->
<resultMap id="BaseResultMap" type="com.learning.newdemo.entity.WxArgument">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="conversation_id" property="conversationId" jdbcType="BIGINT"/>
<result column="topic" property="topic" jdbcType="VARCHAR"/>
<result column="stance" property="stance" jdbcType="VARCHAR"/>
<result column="content" property="content" jdbcType="LONGVARCHAR"/>
<result column="user_message" property="userMessage" jdbcType="LONGVARCHAR"/>
<result column="sequence" property="sequence" jdbcType="INTEGER"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</resultMap>
<!-- 可复用的列名列表 -->
<sql id="Base_Column_List">
id, conversation_id, topic, stance, content, user_message, sequence, create_time
</sql>
<!-- 按 conversationId 查询并按 sequence 排序 -->
<select id="selectByConversationId" resultMap="BaseResultMap" parameterType="java.lang.Long">
SELECT
<include refid="Base_Column_List"/>
FROM wx_argument_record
WHERE conversation_id = #{conversationId,jdbcType=BIGINT}
ORDER BY sequence
</select>
<!-- 插入新记录 -->
<insert id="insert" parameterType="com.learning.newdemo.entity.WxArgument" useGeneratedKeys="true" keyProperty="id">
INSERT INTO wx_argument_record (
conversation_id, topic, stance, content, user_message, sequence, create_time
)
VALUES (
#{conversationId,jdbcType=BIGINT},
#{topic,jdbcType=VARCHAR},
#{stance,jdbcType=VARCHAR},
#{content,jdbcType=LONGVARCHAR},
#{userMessage,jdbcType=LONGVARCHAR},
#{sequence,jdbcType=INTEGER},
#{createTime,jdbcType=TIMESTAMP}
)
</insert>
</mapper>

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.learning.newdemo.mapper.WxConversationMapper">
<!-- 基础结果映射 -->
<resultMap id="BaseResultMap" type="com.learning.newdemo.entity.WxConversation">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="user_id" property="userId" jdbcType="BIGINT"/>
<result column="type" property="type" jdbcType="VARCHAR"/>
<result column="title" property="title" jdbcType="VARCHAR"/>
<result column="preview" property="preview" jdbcType="VARCHAR"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
</resultMap>
<!-- 可复用的列名列表 -->
<sql id="Base_Column_List">
id, user_id, type, title, preview, create_time, update_time
</sql>
<!-- 按用户ID和类型查询对话活动 (用于接口4.1) -->
<select id="selectByUserId" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List"/>
FROM wx_conversation
WHERE user_id = #{userId}
ORDER BY update_time DESC
</select>
<!-- 插入新对话活动 (用于接口3.1/3.2/3.3) -->
<insert id="insert" parameterType="com.learning.newdemo.entity.WxConversation"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO wx_conversation (
user_id, type, title, preview, create_time, update_time
)
VALUES (
#{userId}, #{type}, #{title}, #{preview}, #{createTime}, #{updateTime}
)
</insert>
<!-- 更新对话预览信息 (用于更新最后一次AI回复的预览) -->
<update id="updatePreview">
UPDATE wx_conversation
SET
preview = #{preview},
update_time = NOW()
WHERE id = #{conversationId}
</update>
</mapper>

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.learning.newdemo.mapper.WxDebateMapper">
<resultMap id="BaseResultMap" type="com.learning.newdemo.entity.WxDebate">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="conversation_id" property="conversationId" jdbcType="BIGINT"/>
<result column="content" property="content" jdbcType="LONGVARCHAR"/>
<result column="user_message" property="userMessage" jdbcType="LONGVARCHAR"/>
<result column="sequence" property="sequence" jdbcType="INTEGER"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
id, conversation_id, content, user_message, sequence, create_time
</sql>
<select id="selectByConversationId" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from wx_debate_record
where conversation_id = #{conversationId}
ORDER BY sequence
</select>
<insert id="insert" parameterType="com.learning.newdemo.entity.WxDebate"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO wx_debate_record (
conversation_id, content, user_message, sequence, create_time
)
VALUES (
#{conversationId,jdbcType=BIGINT},
#{content,jdbcType=LONGNVARCHAR},
#{userMessage,jdbcType=LONGNVARCHAR},
#{sequence,jdbcType=INTEGER},
#{createTime, jdbcType=TIMESTAMP}
)
</insert>
</mapper>

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.learning.newdemo.mapper.WxReviewMapper">
<resultMap id="BaseResultMap" type="com.learning.newdemo.entity.WxReview">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="conversation_id" property="conversationId" jdbcType="BIGINT"/>
<result column="content" property="content" jdbcType="LONGVARCHAR"/>
<result column="user_message" property="userMessage" jdbcType="LONGVARCHAR"/>
<result column="sequence" property="sequence" jdbcType="INTEGER"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
id, conversation_id, content, user_message, sequence, create_time
</sql>
<select id="selectByConversationId" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from wx_review_record
where conversation_id = #{conversationId}
ORDER BY sequence
</select>
<insert id="insert" parameterType="com.learning.newdemo.entity.WxDebate"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO wx_review_record (
conversation_id, content, user_message, sequence, create_time
)
VALUES (
#{conversationId,jdbcType=BIGINT},
#{content,jdbcType=LONGNVARCHAR},
#{userMessage,jdbcType=LONGNVARCHAR},
#{sequence,jdbcType=INTEGER},
#{createTime, jdbcType=TIMESTAMP}
)
</insert>
</mapper>

@ -5,7 +5,7 @@ spring:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/wx_miniapp?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
password: 1234
mybatis:
mapper-locations: classpath:mapper/*.xml

@ -1,22 +0,0 @@
-- 创建数据库
CREATE DATABASE IF NOT EXISTS wx_miniapp DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
-- 使用数据库
USE wx_miniapp;
-- 创建微信用户表
CREATE TABLE IF NOT EXISTS `wx_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`openid` varchar(100) NOT NULL COMMENT '微信openid',
`nickname` varchar(50) DEFAULT NULL COMMENT '昵称',
`avatar_url` varchar(500) DEFAULT NULL COMMENT '头像URL',
`gender` tinyint(4) DEFAULT NULL COMMENT '性别 0-未知 1-男 2-女',
`country` varchar(50) DEFAULT NULL COMMENT '国家',
`province` varchar(50) DEFAULT NULL COMMENT '省份',
`city` varchar(50) DEFAULT NULL COMMENT '城市',
`language` varchar(50) DEFAULT NULL COMMENT '语言',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_openid` (`openid`) COMMENT 'openid唯一索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微信用户表';

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.learning.newdemo.mapper.WxArgumentMapper">
<!-- 基础结果映射 -->
<resultMap id="BaseResultMap" type="com.learning.newdemo.entity.WxArgument">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="conversation_id" property="conversationId" jdbcType="BIGINT"/>
<result column="topic" property="topic" jdbcType="VARCHAR"/>
<result column="stance" property="stance" jdbcType="VARCHAR"/>
<result column="content" property="content" jdbcType="LONGVARCHAR"/>
<result column="user_message" property="userMessage" jdbcType="LONGVARCHAR"/>
<result column="sequence" property="sequence" jdbcType="INTEGER"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</resultMap>
<!-- 可复用的列名列表 -->
<sql id="Base_Column_List">
id, conversation_id, topic, stance, content, user_message, sequence, create_time
</sql>
<!-- 按 conversationId 查询并按 sequence 排序 -->
<select id="selectByConversationId" resultMap="BaseResultMap" parameterType="java.lang.Long">
SELECT
<include refid="Base_Column_List"/>
FROM wx_argument_record
WHERE conversation_id = #{conversationId,jdbcType=BIGINT}
ORDER BY sequence
</select>
<!-- 插入新记录 -->
<insert id="insert" parameterType="com.learning.newdemo.entity.WxArgument" useGeneratedKeys="true" keyProperty="id">
INSERT INTO wx_argument_record (
conversation_id, topic, stance, content, user_message, sequence, create_time
)
VALUES (
#{conversationId,jdbcType=BIGINT},
#{topic,jdbcType=VARCHAR},
#{stance,jdbcType=VARCHAR},
#{content,jdbcType=LONGVARCHAR},
#{userMessage,jdbcType=LONGVARCHAR},
#{sequence,jdbcType=INTEGER},
#{createTime,jdbcType=TIMESTAMP}
)
</insert>
</mapper>

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.learning.newdemo.mapper.WxConversationMapper">
<!-- 基础结果映射 -->
<resultMap id="BaseResultMap" type="com.learning.newdemo.entity.WxConversation">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="user_id" property="userId" jdbcType="BIGINT"/>
<result column="type" property="type" jdbcType="VARCHAR"/>
<result column="title" property="title" jdbcType="VARCHAR"/>
<result column="preview" property="preview" jdbcType="VARCHAR"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP"/>
</resultMap>
<!-- 可复用的列名列表 -->
<sql id="Base_Column_List">
id, user_id, type, title, preview, create_time, update_time
</sql>
<!-- 按用户ID和类型查询对话活动 (用于接口4.1) -->
<select id="selectByUserId" resultMap="BaseResultMap">
SELECT <include refid="Base_Column_List"/>
FROM wx_conversation
WHERE user_id = #{userId}
ORDER BY update_time DESC
</select>
<!-- 插入新对话活动 (用于接口3.1/3.2/3.3) -->
<insert id="insert" parameterType="com.learning.newdemo.entity.WxConversation"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO wx_conversation (
user_id, type, title, preview, create_time, update_time
)
VALUES (
#{userId}, #{type}, #{title}, #{preview}, #{createTime}, #{updateTime}
)
</insert>
<!-- 更新对话预览信息 (用于更新最后一次AI回复的预览) -->
<update id="updatePreview">
UPDATE wx_conversation
SET
preview = #{preview},
update_time = NOW()
WHERE id = #{conversationId}
</update>
</mapper>

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.learning.newdemo.mapper.WxDebateMapper">
<resultMap id="BaseResultMap" type="com.learning.newdemo.entity.WxDebate">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="conversation_id" property="conversationId" jdbcType="BIGINT"/>
<result column="content" property="content" jdbcType="LONGVARCHAR"/>
<result column="user_message" property="userMessage" jdbcType="LONGVARCHAR"/>
<result column="sequence" property="sequence" jdbcType="INTEGER"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
id, conversation_id, content, user_message, sequence, create_time
</sql>
<select id="selectByConversationId" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from wx_debate_record
where conversation_id = #{conversationId}
ORDER BY sequence
</select>
<insert id="insert" parameterType="com.learning.newdemo.entity.WxDebate"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO wx_debate_record (
conversation_id, content, user_message, sequence, create_time
)
VALUES (
#{conversationId,jdbcType=BIGINT},
#{content,jdbcType=LONGNVARCHAR},
#{userMessage,jdbcType=LONGNVARCHAR},
#{sequence,jdbcType=INTEGER},
#{createTime, jdbcType=TIMESTAMP}
)
</insert>
</mapper>

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.learning.newdemo.mapper.WxReviewMapper">
<resultMap id="BaseResultMap" type="com.learning.newdemo.entity.WxReview">
<id column="id" property="id" jdbcType="BIGINT"/>
<result column="conversation_id" property="conversationId" jdbcType="BIGINT"/>
<result column="content" property="content" jdbcType="LONGVARCHAR"/>
<result column="user_message" property="userMessage" jdbcType="LONGVARCHAR"/>
<result column="sequence" property="sequence" jdbcType="INTEGER"/>
<result column="create_time" property="createTime" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="Base_Column_List">
id, conversation_id, content, user_message, sequence, create_time
</sql>
<select id="selectByConversationId" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from wx_review_record
where conversation_id = #{conversationId}
ORDER BY sequence
</select>
<insert id="insert" parameterType="com.learning.newdemo.entity.WxDebate"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO wx_review_record (
conversation_id, content, user_message, sequence, create_time
)
VALUES (
#{conversationId,jdbcType=BIGINT},
#{content,jdbcType=LONGNVARCHAR},
#{userMessage,jdbcType=LONGNVARCHAR},
#{sequence,jdbcType=INTEGER},
#{createTime, jdbcType=TIMESTAMP}
)
</insert>
</mapper>

@ -1,19 +0,0 @@
create database if not exists wx_miniapp default charset utf8mb4;
use wx_miniapp;
CREATE TABLE IF NOT EXISTS `wx_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`openid` varchar(100) NOT NULL COMMENT '微信openid',
`nickname` varchar(50) DEFAULT NULL COMMENT '昵称',
`avatar_url` varchar(500) DEFAULT NULL COMMENT '头像URL',
`gender` tinyint(4) DEFAULT NULL COMMENT '性别 0-未知 1-男 2-女',
`country` varchar(50) DEFAULT NULL COMMENT '国家',
`province` varchar(50) DEFAULT NULL COMMENT '省份',
`city` varchar(50) DEFAULT NULL COMMENT '城市',
`language` varchar(50) DEFAULT NULL COMMENT '语言',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_openid` (`openid`) COMMENT 'openid唯一索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='微信用户表';
Loading…
Cancel
Save