@ -1,357 +0,0 @@ | |||
# 小程序登录API接口文档 | |||
## 概述 | |||
本文档描述小程序登录模块的API接口,包括登录、用户管理、token管理等功能。 | |||
## 基础信息 | |||
- **基础URL**: `http://your-domain/applet/login` | |||
- **请求方式**: GET/POST | |||
- **数据格式**: JSON | |||
- **字符编码**: UTF-8 | |||
## 通用响应格式 | |||
```json | |||
{ | |||
"success": true, | |||
"message": "操作成功", | |||
"code": 200, | |||
"result": {} | |||
} | |||
``` | |||
## 接口列表 | |||
### 1. 微信小程序登录 | |||
**接口地址**: `POST /wxLogin` | |||
**请求参数**: | |||
| 参数名 | 类型 | 必填 | 说明 | | |||
|--------|------|------|------| | |||
| code | String | 是 | 微信登录code | | |||
**请求示例**: | |||
```bash | |||
curl -X POST "http://your-domain/applet/login/wxLogin" \ | |||
-H "Content-Type: application/x-www-form-urlencoded" \ | |||
-d "code=wx_login_code_here" | |||
``` | |||
**响应示例**: | |||
```json | |||
{ | |||
"success": true, | |||
"message": "登录成功", | |||
"code": 200, | |||
"result": { | |||
"token": "eyJhbGciOiJIUzI1NiJ9...", | |||
"userInfo": { | |||
"id": "applet_user_123", | |||
"name": "微信用户12345678", | |||
"openid": "wx_openid_123", | |||
"phone": "13800138000", | |||
"avatar": "https://example.com/avatar.jpg", | |||
"bmi": 22.5, | |||
"fat": 15.2 | |||
}, | |||
"openid": "wx_openid_123", | |||
"sessionKey": "session_key_123" | |||
} | |||
} | |||
``` | |||
### 2. 获取用户手机号 | |||
**接口地址**: `POST /getPhoneNumber` | |||
**请求参数**: | |||
| 参数名 | 类型 | 必填 | 说明 | | |||
|--------|------|------|------| | |||
| code | String | 是 | 手机号获取code | | |||
**请求示例**: | |||
```bash | |||
curl -X POST "http://your-domain/applet/login/getPhoneNumber" \ | |||
-H "Content-Type: application/x-www-form-urlencoded" \ | |||
-d "code=phone_code_here" | |||
``` | |||
**响应示例**: | |||
```json | |||
{ | |||
"success": true, | |||
"message": "获取成功", | |||
"code": 200, | |||
"result": "13800138000" | |||
} | |||
``` | |||
### 3. 绑定手机号到用户 | |||
**接口地址**: `POST /bindPhoneNumber` | |||
**请求参数**: | |||
| 参数名 | 类型 | 必填 | 说明 | | |||
|--------|------|------|------| | |||
| token | String | 是 | 用户token | | |||
| phoneCode | String | 是 | 手机号获取code | | |||
**请求示例**: | |||
```bash | |||
curl -X POST "http://your-domain/applet/login/bindPhoneNumber" \ | |||
-H "Content-Type: application/x-www-form-urlencoded" \ | |||
-d "token=user_token_here&phoneCode=phone_code_here" | |||
``` | |||
**响应示例**: | |||
```json | |||
{ | |||
"success": true, | |||
"message": "绑定成功", | |||
"code": 200, | |||
"result": "绑定成功" | |||
} | |||
``` | |||
### 4. 刷新token | |||
**接口地址**: `POST /refreshToken` | |||
**请求参数**: | |||
| 参数名 | 类型 | 必填 | 说明 | | |||
|--------|------|------|------| | |||
| token | String | 是 | 原token | | |||
**请求示例**: | |||
```bash | |||
curl -X POST "http://your-domain/applet/login/refreshToken" \ | |||
-H "Content-Type: application/x-www-form-urlencoded" \ | |||
-d "token=old_token_here" | |||
``` | |||
**响应示例**: | |||
```json | |||
{ | |||
"success": true, | |||
"message": "刷新成功", | |||
"code": 200, | |||
"result": "eyJhbGciOiJIUzI1NiJ9..." | |||
} | |||
``` | |||
### 5. 退出登录 | |||
**接口地址**: `POST /logout` | |||
**请求参数**: | |||
| 参数名 | 类型 | 必填 | 说明 | | |||
|--------|------|------|------| | |||
| token | String | 是 | 用户token | | |||
**请求示例**: | |||
```bash | |||
curl -X POST "http://your-domain/applet/login/logout" \ | |||
-H "Content-Type: application/x-www-form-urlencoded" \ | |||
-d "token=user_token_here" | |||
``` | |||
**响应示例**: | |||
```json | |||
{ | |||
"success": true, | |||
"message": "退出成功", | |||
"code": 200, | |||
"result": "退出成功" | |||
} | |||
``` | |||
### 6. 检查登录状态 | |||
**接口地址**: `GET /checkLogin` | |||
**请求参数**: | |||
| 参数名 | 类型 | 必填 | 说明 | | |||
|--------|------|------|------| | |||
| token | String | 是 | 用户token | | |||
**请求示例**: | |||
```bash | |||
curl -X GET "http://your-domain/applet/login/checkLogin?token=user_token_here" | |||
``` | |||
**响应示例**: | |||
```json | |||
{ | |||
"success": true, | |||
"message": "登录有效", | |||
"code": 200, | |||
"result": { | |||
"id": "applet_user_123", | |||
"name": "微信用户12345678", | |||
"openid": "wx_openid_123", | |||
"phone": "13800138000", | |||
"avatar": "https://example.com/avatar.jpg", | |||
"bmi": 22.5, | |||
"fat": 15.2 | |||
} | |||
} | |||
``` | |||
### 7. 获取用户信息 | |||
**接口地址**: `GET /getUserInfo` | |||
**请求参数**: | |||
| 参数名 | 类型 | 必填 | 说明 | | |||
|--------|------|------|------| | |||
| token | String | 是 | 用户token | | |||
**请求示例**: | |||
```bash | |||
curl -X GET "http://your-domain/applet/login/getUserInfo?token=user_token_here" | |||
``` | |||
**响应示例**: | |||
```json | |||
{ | |||
"success": true, | |||
"message": "获取成功", | |||
"code": 200, | |||
"result": { | |||
"id": "applet_user_123", | |||
"name": "微信用户12345678", | |||
"openid": "wx_openid_123", | |||
"phone": "13800138000", | |||
"avatar": "https://example.com/avatar.jpg", | |||
"bmi": 22.5, | |||
"fat": 15.2 | |||
} | |||
} | |||
``` | |||
### 8. 更新用户信息 | |||
**接口地址**: `POST /updateUserInfo` | |||
**请求参数**: | |||
| 参数名 | 类型 | 必填 | 说明 | | |||
|--------|------|------|------| | |||
| token | String | 是 | 用户token | | |||
| userInfo | Object | 是 | 用户信息对象 | | |||
**请求示例**: | |||
```bash | |||
curl -X POST "http://your-domain/applet/login/updateUserInfo" \ | |||
-H "Content-Type: application/json" \ | |||
-d '{ | |||
"token": "user_token_here", | |||
"userInfo": { | |||
"name": "新昵称", | |||
"avatar": "https://example.com/new_avatar.jpg", | |||
"bmi": 23.0, | |||
"fat": 16.0 | |||
} | |||
}' | |||
``` | |||
**响应示例**: | |||
```json | |||
{ | |||
"success": true, | |||
"message": "更新成功", | |||
"code": 200, | |||
"result": "更新成功" | |||
} | |||
``` | |||
## 错误码说明 | |||
| 错误码 | 说明 | | |||
|--------|------| | |||
| 200 | 成功 | | |||
| 400 | 请求参数错误 | | |||
| 401 | 未授权/token无效 | | |||
| 403 | 禁止访问 | | |||
| 404 | 资源不存在 | | |||
| 500 | 服务器内部错误 | | |||
## 常见错误响应 | |||
### 1. token无效 | |||
```json | |||
{ | |||
"success": false, | |||
"message": "token无效", | |||
"code": 401, | |||
"result": null | |||
} | |||
``` | |||
### 2. 用户不存在 | |||
```json | |||
{ | |||
"success": false, | |||
"message": "用户不存在", | |||
"code": 404, | |||
"result": null | |||
} | |||
``` | |||
### 3. 微信登录失败 | |||
```json | |||
{ | |||
"success": false, | |||
"message": "微信登录失败: code无效", | |||
"code": 400, | |||
"result": null | |||
} | |||
``` | |||
### 4. 手机号已被绑定 | |||
```json | |||
{ | |||
"success": false, | |||
"message": "该手机号已被其他用户绑定", | |||
"code": 400, | |||
"result": null | |||
} | |||
``` | |||
## 使用流程 | |||
### 1. 小程序登录流程 | |||
1. 小程序端调用 `wx.login()` 获取code | |||
2. 调用 `/wxLogin` 接口进行登录 | |||
3. 保存返回的token用于后续请求 | |||
### 2. 手机号绑定流程 | |||
1. 小程序端调用 `wx.getPhoneNumber()` 获取手机号code | |||
2. 调用 `/getPhoneNumber` 接口获取手机号 | |||
3. 调用 `/bindPhoneNumber` 接口绑定手机号到用户 | |||
### 3. token管理流程 | |||
1. 定期调用 `/refreshToken` 刷新token | |||
2. 退出时调用 `/logout` 接口 | |||
3. 使用 `/checkLogin` 检查登录状态 | |||
## 安全注意事项 | |||
1. **token安全**: token应该安全存储,不要暴露给第三方 | |||
2. **HTTPS**: 生产环境必须使用HTTPS | |||
3. **参数验证**: 客户端应该验证所有参数 | |||
4. **错误处理**: 客户端应该妥善处理各种错误情况 | |||
5. **日志记录**: 重要操作应该记录日志 | |||
## 性能优化建议 | |||
1. **缓存**: 用户信息可以适当缓存 | |||
2. **连接池**: 数据库和Redis连接池配置合理 | |||
3. **异步处理**: 非关键操作可以使用异步处理 | |||
4. **监控**: 添加接口调用监控和性能指标 | |||
## 测试建议 | |||
1. **单元测试**: 为每个接口编写单元测试 | |||
2. **集成测试**: 测试完整的登录流程 | |||
3. **压力测试**: 测试高并发场景 | |||
4. **安全测试**: 测试各种异常情况 |
@ -1,224 +0,0 @@ | |||
# AppletShiroRealm 触发问题分析 | |||
## 问题原因分析 | |||
### 1. 主要问题 | |||
`AppletShiroRealm` 没有被触发的主要原因是: | |||
1. **Shiro配置问题**: 在 `ShiroConfig.java` 中,`shiroFilter` 方法使用的是 `SecurityManager` 参数,但这个参数绑定的是 `securityManager` Bean,而不是 `appletSecurityManager`。 | |||
2. **过滤器配置问题**: 虽然配置了 `AppletJwtFilter`,但它没有正确关联到 `AppletShiroRealm`。 | |||
3. **用户服务接口问题**: `IAppletUserService` 的包路径发生了变化,导致依赖注入失败。 | |||
### 2. 具体问题点 | |||
#### 2.1 Shiro配置问题 | |||
```java | |||
// 原来的配置 | |||
@Bean("shiroFilterFactoryBean") | |||
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { | |||
// 这里使用的是 securityManager,而不是 appletSecurityManager | |||
} | |||
``` | |||
#### 2.2 过滤器链配置问题 | |||
```java | |||
// 小程序请求应该使用 appletApi 过滤器 | |||
filterChainDefinitionMap.put("/appletApi/**", "appletApi"); | |||
``` | |||
#### 2.3 用户服务依赖问题 | |||
```java | |||
// 原来的包路径 | |||
import org.jeecg.modules.appletBackground.appletUser.service.IAppletUserService; | |||
// 修改后的包路径 | |||
import org.jeecg.common.api.IAppletUserService; | |||
``` | |||
## 解决方案 | |||
### 1. 修复Shiro配置 | |||
#### 1.1 修改ShiroConfig.java | |||
- 在 `shiroFilter` 方法中添加小程序登录接口的匿名访问配置 | |||
- 确保小程序请求使用正确的过滤器 | |||
```java | |||
// 小程序登录相关接口不需要认证 | |||
filterChainDefinitionMap.put("/appletApi/login/wxLogin", "anon"); | |||
filterChainDefinitionMap.put("/appletApi/login/getPhoneNumber", "anon"); | |||
// applet专用过滤器,只处理/applet开头的请求 | |||
filterChainDefinitionMap.put("/appletApi/**", "appletApi"); | |||
``` | |||
#### 1.2 修复AppletJwtFilter | |||
- 添加登录接口的匿名访问检查 | |||
- 完善token验证逻辑 | |||
- 增加详细的错误日志 | |||
```java | |||
// 检查是否是登录相关接口,这些接口不需要认证 | |||
if (requestPath.startsWith("/appletApi/login/wxLogin") || | |||
requestPath.startsWith("/appletApi/login/getPhoneNumber")) { | |||
return true; | |||
} | |||
``` | |||
### 2. 修复用户服务接口 | |||
#### 2.1 创建统一的IAppletUserService接口 | |||
```java | |||
package org.jeecg.common.api; | |||
public interface IAppletUserService { | |||
AppletUser getByOpenid(String openid); | |||
AppletUser getByPhone(String phone); | |||
boolean save(AppletUser user); | |||
boolean updateById(AppletUser user); | |||
} | |||
``` | |||
#### 2.2 实现服务类 | |||
```java | |||
@Service | |||
public class AppletUserServiceImpl extends ServiceImpl<AppletUserMapper, AppletUser> | |||
implements IAppletUserService { | |||
// 实现具体方法 | |||
} | |||
``` | |||
### 3. 修复AppletShiroRealm | |||
#### 3.1 完善用户获取逻辑 | |||
```java | |||
private AppletUser getAppletUser(String openid) { | |||
try { | |||
// 从数据库查询用户信息 | |||
AppletUser appletUser = appletUserService.getByOpenid(openid); | |||
if (appletUser != null) { | |||
log.debug("从数据库获取到小程序用户: {}", appletUser.getName()); | |||
return appletUser; | |||
} | |||
log.warn("未找到小程序用户,openid: {}", openid); | |||
return null; | |||
} catch (Exception e) { | |||
log.error("获取小程序用户信息异常,openid: {}", openid, e); | |||
return null; | |||
} | |||
} | |||
``` | |||
#### 3.2 完善权限配置 | |||
```java | |||
@Override | |||
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { | |||
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); | |||
// 小程序用户默认权限 | |||
info.addRole("applet_user"); | |||
info.addStringPermission("applet:user:*"); | |||
return info; | |||
} | |||
``` | |||
### 4. 修复服务层方法 | |||
#### 4.1 使用AppletUserUtil获取当前用户 | |||
```java | |||
public Result<String> bindPhoneNumber(String phoneCode) { | |||
try { | |||
// 获取当前登录用户 | |||
AppletUser currentUser = AppletUserUtil.getCurrentAppletUser(); | |||
if (currentUser == null) { | |||
return Result.error("用户未登录"); | |||
} | |||
// 其他逻辑... | |||
} catch (Exception e) { | |||
log.error("绑定手机号异常", e); | |||
return Result.error("绑定失败: " + e.getMessage()); | |||
} | |||
} | |||
``` | |||
#### 4.2 简化控制器方法 | |||
```java | |||
@GetMapping("/getUserInfo") | |||
public Result<AppletUser> getUserInfo() { | |||
log.info("收到获取用户信息请求"); | |||
return appletApiLoginService.getUserInfo(); | |||
} | |||
``` | |||
## 测试验证 | |||
### 1. 创建测试控制器 | |||
```java | |||
@RestController | |||
@RequestMapping("/appletApi/test") | |||
public class AppletTestController { | |||
@GetMapping("/getCurrentUser") | |||
public Result<AppletUser> getCurrentUser() { | |||
AppletUser currentUser = AppletUserUtil.getCurrentAppletUser(); | |||
if (currentUser == null) { | |||
return Result.error("用户未登录"); | |||
} | |||
return Result.OK("获取成功", currentUser); | |||
} | |||
} | |||
``` | |||
### 2. 测试步骤 | |||
1. 先调用登录接口获取token | |||
2. 使用token调用测试接口 | |||
3. 检查日志中是否有 `AppletShiroRealm` 的调试信息 | |||
4. 验证用户信息是否正确返回 | |||
## 关键修复点总结 | |||
### 1. 配置层面 | |||
- ✅ 修复了Shiro配置中的过滤器链 | |||
- ✅ 添加了小程序登录接口的匿名访问 | |||
- ✅ 确保小程序请求使用正确的过滤器 | |||
### 2. 代码层面 | |||
- ✅ 修复了用户服务接口的包路径问题 | |||
- ✅ 完善了AppletShiroRealm的用户获取逻辑 | |||
- ✅ 添加了详细的日志记录 | |||
- ✅ 使用AppletUserUtil简化用户获取 | |||
### 3. 测试层面 | |||
- ✅ 创建了测试控制器验证功能 | |||
- ✅ 提供了完整的测试步骤 | |||
## 预期效果 | |||
修复后,当访问 `/appletApi/**` 路径的请求时: | |||
1. **AppletJwtFilter** 会被触发 | |||
2. **AppletShiroRealm** 会进行用户认证 | |||
3. **AppletUserUtil** 可以正确获取当前用户 | |||
4. 日志中会显示相关的调试信息 | |||
## 注意事项 | |||
1. **包路径**: 确保所有相关的import语句都使用正确的包路径 | |||
2. **Bean注入**: 确保 `IAppletUserService` 的实现类被正确注册为Spring Bean | |||
3. **数据库**: 确保 `applet_user` 表存在且有数据 | |||
4. **Redis**: 确保Redis服务正常运行 | |||
5. **日志级别**: 建议将 `AppletShiroRealm` 的日志级别设置为DEBUG,便于调试 | |||
## 调试建议 | |||
1. 在 `AppletShiroRealm` 的关键方法中添加日志 | |||
2. 检查Spring Bean是否正确注入 | |||
3. 验证数据库连接和查询是否正常 | |||
4. 确认Redis缓存是否正常工作 | |||
5. 使用测试接口逐步验证功能 |
@ -1,201 +0,0 @@ | |||
# 小程序基础查询接口文档 | |||
## 概述 | |||
本文档描述了小程序基础的不需要登录的查询接口,包括产品、Banner、配置信息等模块的查询功能。 | |||
## 接口列表 | |||
### 1. 产品模块 (Product) | |||
#### 1.1 产品列表查询 | |||
- **接口地址**: `GET /applet/product/list` | |||
- **接口描述**: 分页查询产品,支持按分类、关键词筛选 | |||
- **请求参数**: | |||
- `type` (必填): 产品类型 | |||
- `pageNo` (可选): 页码,默认1 | |||
- `pageSize` (可选): 每页大小,默认10 | |||
- `classId` (可选): 分类ID | |||
- `keyword` (可选): 关键词,支持产品名称、描述、详情模糊搜索 | |||
- **响应示例**: | |||
```json | |||
{ | |||
"success": true, | |||
"message": "操作成功!", | |||
"code": 200, | |||
"result": { | |||
"records": [ | |||
{ | |||
"id": "xxx", | |||
"name": "产品名称", | |||
"info": "产品描述", | |||
"type": "产品类型", | |||
"classId": "分类ID", | |||
"originalPrice": 100.00, | |||
"currentPrice": 80.00, | |||
"unit": "单位", | |||
"detail": "产品详情", | |||
"sold": 100, | |||
"content": "产品内容" | |||
} | |||
], | |||
"total": 100, | |||
"size": 10, | |||
"current": 1 | |||
} | |||
} | |||
``` | |||
#### 1.2 产品详情查询 | |||
- **接口地址**: `GET /applet/product/detail` | |||
- **接口描述**: 获取单个产品详细信息 | |||
- **请求参数**: | |||
- `id` (必填): 产品ID | |||
- **响应示例**: | |||
```json | |||
{ | |||
"success": true, | |||
"message": "操作成功!", | |||
"code": 200, | |||
"result": { | |||
"id": "xxx", | |||
"name": "产品名称", | |||
"info": "产品描述", | |||
"type": "产品类型", | |||
"classId": "分类ID", | |||
"originalPrice": 100.00, | |||
"currentPrice": 80.00, | |||
"unit": "单位", | |||
"detail": "产品详情", | |||
"sold": 100, | |||
"content": "产品内容" | |||
} | |||
} | |||
``` | |||
#### 1.3 产品分类查询 | |||
- **接口地址**: `GET /applet/product/category` | |||
- **接口描述**: 根据类型查询产品分类 | |||
- **请求参数**: | |||
- `type` (必填): 产品类型 | |||
- **响应示例**: | |||
```json | |||
{ | |||
"success": true, | |||
"message": "操作成功!", | |||
"code": 200, | |||
"result": [ | |||
{ | |||
"id": "xxx", | |||
"name": "分类名称", | |||
"description": "分类描述", | |||
"sortOrder": 1, | |||
"type": "产品类型" | |||
} | |||
] | |||
} | |||
``` | |||
### 2. Banner模块 (Banner) | |||
#### 2.1 Banner列表查询 | |||
- **接口地址**: `GET /applet/banner/list` | |||
- **接口描述**: 获取Banner列表,按类型分组,按排序字段排序 | |||
- **请求参数**: 无 | |||
- **响应示例**: | |||
```json | |||
{ | |||
"success": true, | |||
"message": "操作成功!", | |||
"code": 200, | |||
"result": { | |||
"home": [ | |||
{ | |||
"id": "xxx", | |||
"imageUrl": "图片地址", | |||
"linkUrl": "跳转链接", | |||
"sortOrder": 1, | |||
"type": "home" | |||
} | |||
], | |||
"product": [ | |||
{ | |||
"id": "xxx", | |||
"imageUrl": "图片地址", | |||
"linkUrl": "跳转链接", | |||
"sortOrder": 1, | |||
"type": "product" | |||
} | |||
] | |||
} | |||
} | |||
``` | |||
### 3. 配置信息模块 (Config) | |||
#### 3.1 配置列表查询 | |||
- **接口地址**: `GET /applet/config/list` | |||
- **接口描述**: 查询所有配置信息 | |||
- **请求参数**: 无 | |||
- **响应示例**: | |||
```json | |||
{ | |||
"success": true, | |||
"message": "操作成功!", | |||
"code": 200, | |||
"result": [ | |||
{ | |||
"id": "xxx", | |||
"code": "配置编码", | |||
"info": "配置描述", | |||
"content": "配置内容", | |||
"type": "配置类型" | |||
} | |||
] | |||
} | |||
``` | |||
## 技术特点 | |||
1. **Lambda查询**: 所有数据库查询都使用MyBatis-Plus的LambdaQueryWrapper,提供类型安全的查询 | |||
2. **模块化设计**: 按业务模块分类,每个模块独立的Controller和Service | |||
3. **复用性高**: 数据库操作复用demo模块的Mapper,避免重复代码 | |||
4. **统一响应**: 使用统一的Result响应格式 | |||
5. **参数校验**: 必填参数校验,可选参数支持默认值 | |||
6. **日志记录**: 所有接口都有详细的日志记录 | |||
## 使用示例 | |||
### 查询产品列表 | |||
```bash | |||
curl -X GET "http://localhost:8080/applet/product/list?type=1&pageNo=1&pageSize=10&keyword=测试" | |||
``` | |||
### 查询产品详情 | |||
```bash | |||
curl -X GET "http://localhost:8080/applet/product/detail?id=xxx" | |||
``` | |||
### 查询产品分类 | |||
```bash | |||
curl -X GET "http://localhost:8080/applet/product/category?type=1" | |||
``` | |||
### 查询Banner列表 | |||
```bash | |||
curl -X GET "http://localhost:8080/applet/banner/list" | |||
``` | |||
### 查询配置列表 | |||
```bash | |||
curl -X GET "http://localhost:8080/applet/config/list" | |||
``` | |||
## 注意事项 | |||
1. 所有接口都不需要登录认证 | |||
2. 产品列表查询的type参数为必填项 | |||
3. 分页参数pageNo从1开始 | |||
4. 关键词搜索支持产品名称、描述、详情的模糊匹配 | |||
5. Banner按类型分组返回,便于前端按需使用 | |||
6. 配置信息按编码排序返回 |
@ -1,272 +0,0 @@ | |||
# 小程序模块使用说明 | |||
## 概述 | |||
本模块为健康管理小程序提供后端服务支持,包含登录、用户管理、微信功能等核心功能。 | |||
## 目录结构 | |||
``` | |||
jeecgboot-boot-applet/ | |||
├── src/main/java/org/jeecg/modules/ | |||
│ ├── applet/ # 小程序核心模块 | |||
│ │ ├── controller/ # 控制器层 | |||
│ │ │ ├── AppletLoginController.java # 登录控制器 | |||
│ │ │ ├── AppletUserController.java # 用户控制器 | |||
│ │ │ └── WxAppletController.java # 微信控制器 | |||
│ │ └── service/ # 服务层 | |||
│ │ ├── AppletLoginService.java # 登录服务 | |||
│ │ ├── AppletUserService.java # 用户服务 | |||
│ │ └── WxAppletService.java # 微信服务 | |||
│ └── common/ | |||
│ └── wxUtils/ # 微信工具类 | |||
│ ├── WxHttpUtils.java # 微信HTTP工具 | |||
│ └── WxHttpClientUtil.java # 微信HTTP客户端 | |||
└── src/main/resources/ | |||
└── application-applet.yml # 小程序配置文件 | |||
``` | |||
## 功能模块 | |||
### 1. 登录模块 (AppletLoginController) | |||
#### 接口列表 | |||
- `POST /applet/login/wxLogin` - 微信小程序登录 | |||
- `POST /applet/login/getPhoneNumber` - 获取用户手机号 | |||
- `POST /applet/login/refreshToken` - 刷新token | |||
- `POST /applet/login/logout` - 退出登录 | |||
- `GET /applet/login/checkLogin` - 检查登录状态 | |||
#### 使用示例 | |||
```javascript | |||
// 小程序登录 | |||
wx.login({ | |||
success: (res) => { | |||
if (res.code) { | |||
// 发送 res.code 到后台换取 openId, sessionKey, unionId | |||
wx.request({ | |||
url: 'http://your-domain/applet/login/wxLogin', | |||
method: 'POST', | |||
data: { | |||
code: res.code | |||
}, | |||
success: (result) => { | |||
console.log('登录成功', result.data); | |||
// 保存token | |||
wx.setStorageSync('token', result.data.result.token); | |||
} | |||
}); | |||
} | |||
} | |||
}); | |||
``` | |||
### 2. 用户模块 (AppletUserController) | |||
#### 接口列表 | |||
- `GET /applet/user/info` - 获取用户信息 | |||
- `POST /applet/user/update` - 更新用户信息 | |||
- `GET /applet/user/health` - 获取健康信息 | |||
- `POST /applet/user/health/update` - 更新健康信息 | |||
- `GET /applet/user/member` - 获取会员信息 | |||
#### 使用示例 | |||
```javascript | |||
// 获取用户信息 | |||
wx.request({ | |||
url: 'http://your-domain/applet/user/info', | |||
method: 'GET', | |||
data: { | |||
userId: 'applet_user_id' | |||
}, | |||
header: { | |||
'Authorization': 'Bearer ' + wx.getStorageSync('token') | |||
}, | |||
success: (result) => { | |||
console.log('用户信息', result.data); | |||
} | |||
}); | |||
``` | |||
### 3. 微信模块 (WxAppletController) | |||
#### 接口列表 | |||
- `POST /applet/wx/qrcode` - 获取小程序码 | |||
- `POST /applet/wx/subscribe/send` - 发送订阅消息 | |||
- `GET /applet/wx/config` - 获取小程序配置 | |||
- `GET /applet/wx/check` - 检查微信服务器 | |||
- `GET /applet/wx/user/info` - 获取微信用户信息 | |||
#### 使用示例 | |||
```javascript | |||
// 获取小程序码 | |||
wx.request({ | |||
url: 'http://your-domain/applet/wx/qrcode', | |||
method: 'POST', | |||
data: { | |||
scene: 'user_id_123', | |||
page: 'pages/index/index' | |||
}, | |||
success: (result) => { | |||
console.log('小程序码', result.data); | |||
} | |||
}); | |||
``` | |||
## 配置说明 | |||
### 1. 微信配置 | |||
在 `application-applet.yml` 中配置微信小程序信息: | |||
```yaml | |||
applet: | |||
wechat: | |||
mpAppId: your_applet_appid | |||
mpAppSecret: your_applet_secret | |||
pay: | |||
mchId: your_mch_id | |||
mchKey: your_mch_key | |||
``` | |||
### 2. 环境变量 | |||
可以通过环境变量覆盖配置: | |||
```bash | |||
export WECHAT_MP_APPID=your_applet_appid | |||
export WECHAT_MP_APPSECRET=your_applet_secret | |||
export WECHAT_MCH_ID=your_mch_id | |||
export WECHAT_MCH_KEY=your_mch_key | |||
``` | |||
### 3. 功能开关 | |||
可以通过配置文件控制功能模块的启用: | |||
```yaml | |||
applet: | |||
features: | |||
login: true # 登录功能 | |||
userInfo: true # 用户信息功能 | |||
healthInfo: true # 健康信息功能 | |||
member: true # 会员功能 | |||
subscribe: true # 订阅消息功能 | |||
qrcode: true # 小程序码功能 | |||
``` | |||
## 安全配置 | |||
### 1. Token配置 | |||
```yaml | |||
applet: | |||
security: | |||
tokenExpireTime: 7200 # token过期时间(秒) | |||
refreshTokenExpireTime: 604800 # 刷新token过期时间(秒) | |||
enableTokenBlacklist: true # 启用token黑名单 | |||
``` | |||
### 2. 接口权限 | |||
所有小程序接口都使用了 `@IgnoreAuth` 注解,表示不需要登录验证。在实际使用中,可以根据需要添加token验证。 | |||
## 日志配置 | |||
```yaml | |||
applet: | |||
logging: | |||
level: INFO | |||
logWxApi: true # 记录微信API调用日志 | |||
logUserAction: true # 记录用户操作日志 | |||
``` | |||
## 缓存配置 | |||
```yaml | |||
applet: | |||
cache: | |||
accessTokenExpire: 7000 # 微信access_token缓存时间(秒) | |||
userInfoExpire: 3600 # 用户信息缓存时间(秒) | |||
qrcodeExpire: 86400 # 小程序码缓存时间(秒) | |||
``` | |||
## 开发说明 | |||
### 1. 数据库集成 | |||
当前版本使用模拟数据,实际使用时需要: | |||
1. 创建用户表 `applet_user` | |||
2. 创建健康信息表 `applet_health_info` | |||
3. 创建会员信息表 `applet_member_info` | |||
4. 在Service层实现数据库操作 | |||
### 2. 微信API集成 | |||
已集成以下微信API: | |||
- 登录:`/sns/jscode2session` | |||
- 获取手机号:`/wxa/business/getuserphonenumber` | |||
- 获取access_token:`/cgi-bin/token` | |||
- 获取小程序码:`/wxa/getwxacodeunlimit` | |||
- 发送订阅消息:`/cgi-bin/message/subscribe/send` | |||
### 3. 错误处理 | |||
所有接口都包含完整的异常处理: | |||
- 微信API调用失败 | |||
- 参数验证失败 | |||
- 数据库操作失败 | |||
- 网络连接失败 | |||
### 4. 扩展开发 | |||
如需添加新功能,可以: | |||
1. 在 `service` 包下创建新的服务类 | |||
2. 在 `controller` 包下创建对应的控制器 | |||
3. 在配置文件中添加相关配置 | |||
4. 更新本文档 | |||
## 部署说明 | |||
### 1. 打包 | |||
```bash | |||
mvn clean package -Dmaven.test.skip=true | |||
``` | |||
### 2. 运行 | |||
```bash | |||
java -jar jeecgboot-boot-applet.jar --spring.profiles.active=prod | |||
``` | |||
### 3. Docker部署 | |||
```dockerfile | |||
FROM openjdk:8-jre-alpine | |||
COPY jeecgboot-boot-applet.jar app.jar | |||
EXPOSE 8080 | |||
ENTRYPOINT ["java", "-jar", "/app.jar"] | |||
``` | |||
## 注意事项 | |||
1. **安全性**:生产环境中请务必配置正确的微信小程序密钥 | |||
2. **性能**:建议对微信API调用结果进行缓存 | |||
3. **监控**:建议添加接口调用监控和日志收集 | |||
4. **测试**:请在小程序开发工具中充分测试所有功能 | |||
5. **文档**:接口文档可通过Swagger UI查看:`http://your-domain/swagger-ui.html` | |||
## 技术支持 | |||
如有问题,请联系开发团队或查看项目文档。 |
@ -1,202 +0,0 @@ | |||
# 小程序登录修复说明 | |||
## 修复的问题 | |||
### 1. 用户信息获取问题 | |||
**原问题**: `AppletShiroRealm` 中的 `getAppletUser` 方法返回null,导致无法正确获取用户信息。 | |||
**修复方案**: | |||
- 完善了 `getAppletUser` 方法,支持从数据库和Redis缓存获取用户信息 | |||
- 添加了用户信息缓存机制,提高性能 | |||
- 增加了异常处理和日志记录 | |||
### 2. Token验证逻辑不完整 | |||
**原问题**: Token验证缺少黑名单检查和刷新机制。 | |||
**修复方案**: | |||
- 添加了token黑名单检查 | |||
- 完善了token刷新逻辑 | |||
- 统一了token管理机制 | |||
### 3. Shiro认证体系集成问题 | |||
**原问题**: 小程序登录没有正确集成到Shiro认证体系。 | |||
**修复方案**: | |||
- 创建了专用的 `AppletShiroConfig` 配置类 | |||
- 完善了 `AppletShiroRealm` 的认证和授权逻辑 | |||
- 添加了小程序用户默认权限配置 | |||
### 4. 控制器参数验证不足 | |||
**原问题**: 控制器缺少参数验证和错误处理。 | |||
**修复方案**: | |||
- 添加了完整的参数验证 | |||
- 增加了Swagger API文档注解 | |||
- 完善了错误处理和日志记录 | |||
## 新增功能 | |||
### 1. 用户工具类 | |||
创建了 `AppletUserUtil` 工具类,提供以下功能: | |||
- `getCurrentAppletUser()`: 获取当前登录的小程序用户 | |||
- `getCurrentAppletUserId()`: 获取当前用户ID | |||
- `getCurrentAppletUserOpenid()`: 获取当前用户openid | |||
- `isAppletUserLoggedIn()`: 检查用户是否已登录 | |||
- `hasPermission()`: 检查用户权限 | |||
- `hasRole()`: 检查用户角色 | |||
### 2. 缓存机制 | |||
- 用户信息缓存(30分钟) | |||
- Token缓存(JWT过期时间的2倍) | |||
- Session_key缓存(7天) | |||
- 手机号临时缓存(5分钟) | |||
- Token黑名单缓存(24小时) | |||
### 3. 权限控制 | |||
- 小程序用户默认角色:`applet_user` | |||
- 小程序用户默认权限:`applet:user:*` | |||
- 支持细粒度权限控制 | |||
## 使用示例 | |||
### 1. 在控制器中获取当前用户 | |||
```java | |||
@GetMapping("/getCurrentUser") | |||
public Result<AppletUser> getCurrentUser() { | |||
AppletUser currentUser = AppletUserUtil.getCurrentAppletUser(); | |||
if (currentUser == null) { | |||
return Result.error("用户未登录"); | |||
} | |||
return Result.OK("获取成功", currentUser); | |||
} | |||
``` | |||
### 2. 权限检查 | |||
```java | |||
@PostMapping("/sensitiveOperation") | |||
public Result<String> sensitiveOperation() { | |||
if (!AppletUserUtil.hasPermission("applet:user:edit")) { | |||
return Result.error("权限不足"); | |||
} | |||
// 执行敏感操作 | |||
return Result.OK("操作成功"); | |||
} | |||
``` | |||
### 3. 角色检查 | |||
```java | |||
@GetMapping("/adminOnly") | |||
public Result<String> adminOnly() { | |||
if (!AppletUserUtil.hasRole("applet_admin")) { | |||
return Result.error("需要管理员权限"); | |||
} | |||
return Result.OK("管理员操作成功"); | |||
} | |||
``` | |||
## 配置要求 | |||
### 1. 数据库配置 | |||
确保 `applet_user` 表已创建,包含以下字段: | |||
- `id`: 主键 | |||
- `openid`: 微信openid(唯一索引) | |||
- `phone`: 手机号(唯一索引) | |||
- `name`: 用户昵称 | |||
- `avatar`: 头像 | |||
- `bmi`: 体总指数 | |||
- `fat`: 脂肪 | |||
- `create_time`: 创建时间 | |||
- `update_time`: 更新时间 | |||
### 2. Redis配置 | |||
确保Redis服务正常运行,用于缓存: | |||
- 用户信息 | |||
- Token缓存 | |||
- Session_key | |||
- 黑名单 | |||
### 3. 微信配置 | |||
在 `application.yml` 中配置: | |||
```yaml | |||
wechat: | |||
mpAppId: your_applet_appid | |||
mpAppSecret: your_applet_secret | |||
``` | |||
### 4. JWT配置 | |||
确保JWT工具类能正确读取配置: | |||
```yaml | |||
jeecg: | |||
jwt: | |||
secret: your_jwt_secret_key | |||
expire: 604800 | |||
``` | |||
## 安全改进 | |||
### 1. Token安全 | |||
- 生产环境不返回session_key | |||
- Token自动刷新机制 | |||
- Token黑名单管理 | |||
- 支持token主动失效 | |||
### 2. 参数验证 | |||
- 所有接口都添加了参数验证 | |||
- 防止空参数和恶意参数 | |||
- 统一的错误处理 | |||
### 3. 权限控制 | |||
- 基于Shiro的权限控制 | |||
- 支持角色和权限检查 | |||
- 细粒度权限管理 | |||
## 性能优化 | |||
### 1. 缓存策略 | |||
- 用户信息缓存减少数据库查询 | |||
- Token缓存提高验证速度 | |||
- 合理的缓存过期时间 | |||
### 2. 异常处理 | |||
- 完善的异常捕获和处理 | |||
- 详细的日志记录 | |||
- 友好的错误提示 | |||
### 3. 并发处理 | |||
- 线程安全的用户信息获取 | |||
- 原子性的token操作 | |||
- 避免并发冲突 | |||
## 测试建议 | |||
### 1. 功能测试 | |||
- 测试完整的登录流程 | |||
- 测试token刷新机制 | |||
- 测试权限控制功能 | |||
- 测试异常情况处理 | |||
### 2. 性能测试 | |||
- 测试高并发登录 | |||
- 测试缓存命中率 | |||
- 测试数据库连接池 | |||
### 3. 安全测试 | |||
- 测试token伪造防护 | |||
- 测试权限绕过防护 | |||
- 测试参数注入防护 | |||
## 注意事项 | |||
1. **生产环境配置**: 确保生产环境使用HTTPS,不要暴露敏感信息 | |||
2. **日志管理**: 合理配置日志级别,避免敏感信息泄露 | |||
3. **监控告警**: 添加关键操作的监控和告警 | |||
4. **备份策略**: 定期备份用户数据和配置信息 | |||
5. **版本兼容**: 注意API版本兼容性,避免影响现有客户端 | |||
## 后续优化建议 | |||
1. **多租户支持**: 如果需要支持多租户,可以扩展用户表结构 | |||
2. **第三方登录**: 可以扩展支持其他第三方登录方式 | |||
3. **消息推送**: 集成消息推送功能,支持实时通知 | |||
4. **数据分析**: 添加用户行为分析功能 | |||
5. **自动化测试**: 编写完整的自动化测试用例 |
@ -1,278 +0,0 @@ | |||
# 小程序模块配置说明 | |||
## 概述 | |||
本文档说明小程序登录服务需要配置的内容,包括数据库、Redis、微信配置等。 | |||
## 1. 数据库配置 | |||
### 1.1 数据库表结构 | |||
需要确保 `applet_user` 表已创建,表结构如下: | |||
```sql | |||
CREATE TABLE `applet_user` ( | |||
`id` varchar(32) NOT NULL COMMENT '主键', | |||
`create_by` varchar(50) DEFAULT NULL COMMENT '创建人', | |||
`create_time` datetime DEFAULT NULL COMMENT '创建日期', | |||
`update_by` varchar(50) DEFAULT NULL COMMENT '更新人', | |||
`update_time` datetime DEFAULT NULL COMMENT '更新日期', | |||
`sys_org_code` varchar(64) DEFAULT NULL COMMENT '所属部门', | |||
`name` varchar(100) DEFAULT NULL COMMENT '昵称', | |||
`openid` varchar(100) DEFAULT NULL COMMENT '第三方认证id', | |||
`phone` varchar(20) DEFAULT NULL COMMENT '手机号', | |||
`bmi` decimal(10,2) DEFAULT NULL COMMENT '体总指数', | |||
`fat` decimal(10,2) DEFAULT NULL COMMENT '脂肪', | |||
`avatar` varchar(500) DEFAULT NULL COMMENT '头像', | |||
PRIMARY KEY (`id`), | |||
UNIQUE KEY `uk_openid` (`openid`), | |||
UNIQUE KEY `uk_phone` (`phone`) | |||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='小程序用户表'; | |||
``` | |||
### 1.2 数据库连接配置 | |||
在 `application.yml` 中配置数据库连接: | |||
```yaml | |||
spring: | |||
datasource: | |||
url: jdbc:mysql://localhost:3306/jeecg-boot?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 | |||
username: root | |||
password: root | |||
driver-class-name: com.mysql.cj.jdbc.Driver | |||
``` | |||
## 2. Redis配置 | |||
### 2.1 Redis连接配置 | |||
在 `application.yml` 中配置Redis: | |||
```yaml | |||
spring: | |||
redis: | |||
host: localhost | |||
port: 6379 | |||
password: | |||
database: 0 | |||
timeout: 10000ms | |||
lettuce: | |||
pool: | |||
max-active: 8 | |||
max-wait: -1ms | |||
max-idle: 8 | |||
min-idle: 0 | |||
``` | |||
### 2.2 Redis配置类 | |||
需要创建Redis配置类: | |||
```java | |||
@Configuration | |||
public class RedisConfig { | |||
@Bean | |||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { | |||
RedisTemplate<String, Object> template = new RedisTemplate<>(); | |||
template.setConnectionFactory(factory); | |||
// 设置key的序列化方式 | |||
template.setKeySerializer(new StringRedisSerializer()); | |||
// 设置value的序列化方式 | |||
template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); | |||
// 设置hash key的序列化方式 | |||
template.setHashKeySerializer(new StringRedisSerializer()); | |||
// 设置hash value的序列化方式 | |||
template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); | |||
template.afterPropertiesSet(); | |||
return template; | |||
} | |||
} | |||
``` | |||
## 3. 微信小程序配置 | |||
### 3.1 微信配置 | |||
在 `application.yml` 中配置微信小程序信息: | |||
```yaml | |||
wechat: | |||
mpAppId: your_applet_appid | |||
mpAppSecret: your_applet_secret | |||
merchantId: your_merchant_id # 如果需要支付功能 | |||
``` | |||
### 3.2 微信配置类 | |||
确保 `WxHttpUtils` 类能正确读取配置: | |||
```java | |||
@Component | |||
public class WxHttpUtils { | |||
@Value("${wechat.mpAppId}") | |||
private String appid; | |||
@Value("${wechat.mpAppSecret}") | |||
private String secret; | |||
} | |||
``` | |||
## 4. JWT配置 | |||
### 4.1 JWT密钥配置 | |||
在 `application.yml` 中配置JWT密钥: | |||
```yaml | |||
jeecg: | |||
jwt: | |||
secret: your_jwt_secret_key | |||
expire: 604800 # 7天,单位秒 | |||
``` | |||
### 4.2 JWT工具类配置 | |||
确保 `JwtUtil` 类能正确读取配置: | |||
```java | |||
@Component | |||
public class JwtUtil { | |||
@Value("${jeecg.jwt.secret}") | |||
private String secret; | |||
@Value("${jeecg.jwt.expire}") | |||
private long expire; | |||
} | |||
``` | |||
## 5. 日志配置 | |||
### 5.1 日志级别配置 | |||
在 `application.yml` 中配置日志级别: | |||
```yaml | |||
logging: | |||
level: | |||
org.jeecg.modules.applet: DEBUG | |||
org.jeecg.modules.common.wxUtils: DEBUG | |||
``` | |||
## 6. 安全配置 | |||
### 6.1 CORS配置 | |||
如果需要跨域访问,需要配置CORS: | |||
```java | |||
@Configuration | |||
public class CorsConfig { | |||
@Bean | |||
public CorsFilter corsFilter() { | |||
CorsConfiguration config = new CorsConfiguration(); | |||
config.addAllowedOrigin("*"); | |||
config.addAllowedHeader("*"); | |||
config.addAllowedMethod("*"); | |||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); | |||
source.registerCorsConfiguration("/**", config); | |||
return new CorsFilter(source); | |||
} | |||
} | |||
``` | |||
## 7. 依赖配置 | |||
### 7.1 Maven依赖 | |||
确保 `pom.xml` 中包含以下依赖: | |||
```xml | |||
<!-- Redis --> | |||
<dependency> | |||
<groupId>org.springframework.boot</groupId> | |||
<artifactId>spring-boot-starter-data-redis</artifactId> | |||
</dependency> | |||
<!-- HTTP客户端 --> | |||
<dependency> | |||
<groupId>org.apache.httpcomponents</groupId> | |||
<artifactId>httpclient</artifactId> | |||
</dependency> | |||
<!-- JSON处理 --> | |||
<dependency> | |||
<groupId>com.alibaba</groupId> | |||
<artifactId>fastjson</artifactId> | |||
</dependency> | |||
<!-- MyBatis Plus --> | |||
<dependency> | |||
<groupId>com.baomidou</groupId> | |||
<artifactId>mybatis-plus-boot-starter</artifactId> | |||
</dependency> | |||
``` | |||
## 8. 环境变量配置 | |||
### 8.1 生产环境配置 | |||
在生产环境中,建议使用环境变量或配置中心来管理敏感信息: | |||
```yaml | |||
wechat: | |||
mpAppId: ${WECHAT_MP_APPID:default_appid} | |||
mpAppSecret: ${WECHAT_MP_SECRET:default_secret} | |||
spring: | |||
redis: | |||
host: ${REDIS_HOST:localhost} | |||
port: ${REDIS_PORT:6379} | |||
password: ${REDIS_PASSWORD:} | |||
``` | |||
## 9. 监控配置 | |||
### 9.1 健康检查 | |||
可以添加健康检查端点: | |||
```yaml | |||
management: | |||
endpoints: | |||
web: | |||
exposure: | |||
include: health,info,metrics | |||
endpoint: | |||
health: | |||
show-details: always | |||
``` | |||
## 10. 注意事项 | |||
1. **安全性**:生产环境中不要将敏感信息硬编码在代码中 | |||
2. **性能**:Redis连接池配置要根据实际负载调整 | |||
3. **监控**:建议添加应用监控和日志收集 | |||
4. **备份**:定期备份数据库和Redis数据 | |||
5. **测试**:在部署前进行充分的测试 | |||
## 11. 常见问题 | |||
### 11.1 Redis连接失败 | |||
- 检查Redis服务是否启动 | |||
- 检查网络连接和防火墙设置 | |||
- 检查Redis配置是否正确 | |||
### 11.2 微信API调用失败 | |||
- 检查微信小程序配置是否正确 | |||
- 检查网络连接是否正常 | |||
- 检查微信API调用频率限制 | |||
### 11.3 数据库连接失败 | |||
- 检查数据库服务是否启动 | |||
- 检查数据库连接配置 | |||
- 检查数据库用户权限 | |||
## 12. 部署检查清单 | |||
- [ ] 数据库表已创建 | |||
- [ ] Redis服务已启动 | |||
- [ ] 微信小程序配置正确 | |||
- [ ] JWT密钥已配置 | |||
- [ ] 日志配置正确 | |||
- [ ] 网络连接正常 | |||
- [ ] 安全配置已设置 | |||
- [ ] 监控已配置 | |||
- [ ] 备份策略已制定 |