Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
A
auth-master
概览
Overview
Details
Activity
Cycle Analytics
版本库
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
问题
0
Issues
0
列表
Board
标记
里程碑
合并请求
0
Merge Requests
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
Snippets
成员
Members
Collapse sidebar
Close sidebar
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
吴超
auth-master
Commits
7b318c8d
Commit
7b318c8d
authored
Apr 14, 2026
by
周海峰
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
no message
parent
a7e1914e
隐藏空白字符变更
内嵌
并排
正在显示
19 个修改的文件
包含
1461 行增加
和
1 行删除
+1461
-1
doc/企业微信内网应用集成方案.md
+585
-0
src/main/java/com/metro/auth/platform/config/WebSecurityConfig.java
+2
-1
src/main/java/com/metro/auth/platform/messagepush/config/WeChatConfig.java
+26
-0
src/main/java/com/metro/auth/platform/messagepush/controller/MessagePushController.java
+177
-0
src/main/java/com/metro/auth/platform/messagepush/model/request/MessageSubmitRequest.java
+51
-0
src/main/java/com/metro/auth/platform/messagepush/model/request/SendMessageRequest.java
+54
-0
src/main/java/com/metro/auth/platform/messagepush/model/request/UserListRequest.java
+20
-0
src/main/java/com/metro/auth/platform/messagepush/model/response/WxDepartment.java
+40
-0
src/main/java/com/metro/auth/platform/messagepush/model/response/WxMessageResult.java
+45
-0
src/main/java/com/metro/auth/platform/messagepush/model/response/WxUser.java
+75
-0
src/main/java/com/metro/auth/platform/messagepush/model/response/WxUserInfo.java
+30
-0
src/main/java/com/metro/auth/platform/messagepush/service/MessagePushService.java
+63
-0
src/main/java/com/metro/auth/platform/messagepush/service/impl/MessagePushServiceImpl.java
+139
-0
src/main/java/com/metro/auth/platform/messagepush/util/WeChatApiUtil.java
+149
-0
src/main/resources/application-dev.yml
+1
-0
src/main/resources/application-prod.yml
+1
-0
src/main/resources/application-sjt.yml
+1
-0
src/main/resources/application-test151.yml
+1
-0
src/main/resources/application-test153.yml
+1
-0
没有找到文件。
doc/企业微信内网应用集成方案.md
0 → 100644
View file @
7b318c8d
# 企业微信内网应用集成方案
# 企业微信内网应用集成方案
## 项目概述
本文档描述了企业微信内网应用与其他企业微信应用的集成方案,实现统一消息推送和应用跳转功能。
## 需求总结
### 当前状况
-
已有部署正常的企业微信内网应用(基于网页)
-
需要集成多个其他企业微信应用(同样基于网页)
-
这些应用已有自己的消息推送机制,但希望统一通过内网应用推送
-
内网应用目前无API接口,使用用户ID+服务器自认证方式
### 核心需求
-
**统一消息推送**
:所有应用消息通过内网应用推送
-
**统一消息收件箱**
:在内网应用中展示所有应用消息
-
**应用跳转**
:点击消息直接跳转到目标应用的相关内容页面
-
**转发页面**
:仅作为跳转中介,无需消息预览
## 系统架构
### 整体架构图
```
企业微信客户端
↓
内网应用前端
↓
内网应用后端 ← 直接接收各应用调用
↑
应用A后端 应用B后端(直接调用内网应用后端API)
```
### 核心模块
-
**消息接收API**
:各应用直接调用内网应用后端API提交消息
-
**消息存储**
:内网应用后端负责存储所有消息
-
**消息推送**
:内网应用后端调用现有的消息发送服务
-
**统一收件箱**
:内网应用前端展示消息列表
-
**跳转转发**
:处理应用间跳转逻辑
## 流程时序图
### 1. 消息推送流程
```
应用A后端 -> 内网应用后端: POST /api/messages (提交消息)
内网应用后端 -> 内网应用后端: 验证应用身份
内网应用后端 -> 内网应用后端: 存储消息到数据库
内网应用后端 -> 现有消息发送服务: 调用推送接口
现有消息发送服务 -> 企业微信: 推送消息给用户
企业微信 -> 用户: 显示通知
```
### 2. 用户查看消息流程
```
用户 -> 企业微信: 点击内网应用
企业微信 -> 内网应用前端: 加载应用
内网应用前端 -> 内网应用后端: GET /api/messages (获取消息列表)
内网应用后端 -> 内网应用前端: 返回消息数据
内网应用前端 -> 用户: 展示统一收件箱
```
### 3. 消息跳转流程
```
用户 -> 内网应用前端: 点击某条消息
内网应用前端 -> 内网应用后端: GET /api/messages/{id}/redirect
内网应用后端 -> 内网应用后端: 记录点击日志
内网应用后端 -> 内网应用前端: 返回目标应用URL
内网应用前端 -> 企业微信: 跳转到目标应用
企业微信 -> 目标应用前端: 加载具体内容
```
## 接口文档
### 1. 消息提交接口
**POST /api/messages**
**功能描述**
:各应用向后端提交消息
**请求头**
:
```
Content-Type: application/json
Authorization: Bearer {app_token}
```
**请求参数**
:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| appId | string | 是 | 应用标识 |
| userId | string | 是 | 目标用户ID |
| title | string | 是 | 消息标题 |
| content | string | 是 | 消息内容 |
| targetUrl | string | 是 | 跳转链接 |
| messageType | string | 是 | 消息类型:text、image、voice、video、file、textcard、mpnews、markdown、miniprogram_notice、template_card |
| timestamp | string | 是 | 时间戳,格式:YYYY-MM-DD HH:MM:SS |
| msgData | object | 否 | 特定消息类型的扩展数据 |
**请求示例**
:
**文本消息**
:
```
json
{
"appId"
:
"hr_system"
,
"userId"
:
"zhangsan"
,
"title"
:
"新的审批任务"
,
"content"
:
"您有一个请假申请需要审批"
,
"targetUrl"
:
"https://hr.company.com/approval/detail/123"
,
"messageType"
:
"text"
,
"timestamp"
:
"2025-11-03 10:30:00"
}
```
**文本卡片消息**
:
```
json
{
"appId"
:
"hr_system"
,
"userId"
:
"zhangsan"
,
"title"
:
"审批提醒"
,
"content"
:
"您有新的请假申请待审批"
,
"targetUrl"
:
"https://hr.company.com/approval/detail/123"
,
"messageType"
:
"textcard"
,
"timestamp"
:
"2025-11-03 10:30:00"
,
"msgData"
:
{
"description"
:
"张三提交了请假申请,请假时间:2025-11-05至2025-11-07"
,
"url"
:
"https://hr.company.com/approval/detail/123"
,
"btnTxt"
:
"立即审批"
}
}
```
**模板卡片消息**
:
```
json
{
"appId"
:
"approval_system"
,
"userId"
:
"zhangsan"
,
"title"
:
"请假审批任务"
,
"content"
:
"新的请假申请待处理"
,
"targetUrl"
:
"https://approval.company.com/task/123"
,
"messageType"
:
"template_card"
,
"timestamp"
:
"2025-11-03 10:30:00"
,
"msgData"
:
{
"cardType"
:
"button_interaction"
,
"source"
:
{
"desc"
:
"人事系统"
,
"descColor"
:
1
},
"mainTitle"
:
{
"title"
:
"请假审批提醒"
,
"desc"
:
"张三申请请假3天"
},
"emphasisContent"
:
{
"title"
:
"3天"
,
"desc"
:
"请假时长"
},
"subTitleText"
:
"请假时间:2025-11-05至2025-11-07"
,
"horizontalContentList"
:
[
{
"keyName"
:
"请假类型"
,
"value"
:
"事假"
},
{
"keyName"
:
"申请时间"
,
"value"
:
"2025-11-03 10:30"
}
],
"jumpList"
:
[
{
"type"
:
1
,
"title"
:
"查看详情"
,
"url"
:
"https://approval.company.com/task/123"
}
],
"cardAction"
:
{
"type"
:
1
,
"url"
:
"https://approval.company.com/task/123"
},
"taskId"
:
"task_123456"
,
"buttonList"
:
[
{
"text"
:
"同意"
,
"style"
:
1
,
"key"
:
"approve"
},
{
"text"
:
"拒绝"
,
"style"
:
2
,
"key"
:
"reject"
}
]
}
}
```
**图片消息**
:
```
json
{
"appId"
:
"project_system"
,
"userId"
:
"zhangsan"
,
"title"
:
"项目截图"
,
"content"
:
"项目进度截图"
,
"targetUrl"
:
"https://project.company.com/detail/456"
,
"messageType"
:
"image"
,
"timestamp"
:
"2025-11-03 10:30:00"
,
"msgData"
:
{
"imageUrl"
:
"https://file.company.com/images/progress_123.jpg"
,
"imageMd5"
:
"abcd1234567890abcdef1234567890ab"
}
}
```
**文件消息**
:
```
json
{
"appId"
:
"doc_system"
,
"userId"
:
"zhangsan"
,
"title"
:
"会议纪要"
,
"content"
:
"本周会议纪要文档"
,
"targetUrl"
:
"https://doc.company.com/file/789"
,
"messageType"
:
"file"
,
"timestamp"
:
"2025-11-03 10:30:00"
,
"msgData"
:
{
"fileName"
:
"会议纪要_20251103.docx"
,
"fileUrl"
:
"https://file.company.com/docs/meeting_20251103.docx"
,
"fileSize"
:
1024000
,
"fileType"
:
"docx"
}
}
```
**Markdown消息**
:
```
json
{
"appId"
:
"tech_system"
,
"userId"
:
"zhangsan"
,
"title"
:
"技术公告"
,
"content"
:
"系统升级通知"
,
"targetUrl"
:
"https://tech.company.com/notice/101"
,
"messageType"
:
"markdown"
,
"timestamp"
:
"2025-11-03 10:30:00"
,
"msgData"
:
{
"markdownContent"
:
"# 系统维护通知
\n\n
**维护时间**:2025-11-05 20:00-24:00
\n\n
**影响范围**:所有业务系统
\n\n
**维护内容**:
\n
- 数据库升级
\n
- 安全补丁更新
\n
- 性能优化"
}
}
```
**响应参数**
:
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | integer | 响应码,200表示成功 |
| message | string | 响应消息 |
| data | object | 响应数据 |
**响应示例**
:
```
json
{
"code"
:
200
,
"message"
:
"success"
,
"data"
:
{
"message_id"
:
"msg_20251103103000123"
,
"response_code"
:
"response_code_abc123"
,
//
仅模板卡片消息返回
"response_code_expire_time"
:
"2025-11-06 10:30:00"
//
仅模板卡片消息返回
}
}
```
**错误码**
:
| 错误码 | 说明 |
|--------|------|
| 400 | 请求参数错误 |
| 401 | 应用认证失败 |
| 500 | 服务器内部错误 |
### 2. 消息列表接口
**GET /api/messages**
**功能描述**
:获取用户消息列表
**请求参数**
:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| userId | string | 是 | 用户ID |
| page | integer | 否 | 页码,默认1 |
| pageSize | integer | 否 | 每页条数,默认20 |
**响应参数**
:
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | integer | 响应码 |
| data | object | 响应数据 |
| total | integer | 总消息数 |
| messages | array | 消息列表 |
**响应示例**
:
```
json
{
"code"
:
200
,
"data"
:
{
"total"
:
100
,
"messages"
:
[
{
"id"
:
"msg_20251103103000123"
,
"app_id"
:
"hr_system"
,
"app_name"
:
"人事系统"
,
"title"
:
"新的审批任务"
,
"content"
:
"您有一个请假申请需要审批"
,
"create_time"
:
"2025-11-03 10:30:00"
,
"is_read"
:
false
,
"message_type"
:
"textcard"
,
"target_url"
:
"https://hr.company.com/approval/detail/123"
,
"msg_data"
:
{
"description"
:
"张三提交了请假申请,请假时间:2025-11-05至2025-11-07"
,
"url"
:
"https://hr.company.com/approval/detail/123"
,
"btntxt"
:
"立即审批"
}
},
{
"id"
:
"msg_20251103102500567"
,
"app_id"
:
"project_system"
,
"app_name"
:
"项目管理系统"
,
"title"
:
"项目进度更新"
,
"content"
:
"项目A已完成阶段评审"
,
"create_time"
:
"2025-11-03 10:25:00"
,
"is_read"
:
true
,
"message_type"
:
"image"
,
"target_url"
:
"https://project.company.com/detail/456"
,
"msg_data"
:
{
"image_url"
:
"https://file.company.com/images/progress_456.jpg"
,
"image_md5"
:
"abcd1234567890abcdef1234567890ab"
}
},
{
"id"
:
"msg_20251103102000987"
,
"app_id"
:
"doc_system"
,
"app_name"
:
"文档系统"
,
"title"
:
"会议纪要"
,
"content"
:
"本周会议纪要文档"
,
"create_time"
:
"2025-11-03 10:20:00"
,
"is_read"
:
false
,
"message_type"
:
"file"
,
"target_url"
:
"https://doc.company.com/file/789"
,
"msg_data"
:
{
"file_name"
:
"会议纪要_20251103.docx"
,
"file_url"
:
"https://file.company.com/docs/meeting_20251103.docx"
,
"file_size"
:
1024000
,
"file_type"
:
"docx"
}
}
]
}
}
```
### 3. 消息跳转接口
**GET /api/messages/{id}/redirect**
**功能描述**
:获取消息跳转链接
**请求参数**
:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| id | string | 是 | 消息ID |
**响应参数**
:
| 参数名 | 类型 | 说明 |
|--------|------|------|
| code | integer | 响应码 |
| data | object | 响应数据 |
| redirect_url | string | 跳转链接 |
**响应示例**
:
```
json
{
"code"
:
200
,
"data"
:
{
"redirect_url"
:
"https://hr.company.com/approval/detail/123"
}
}
```
### 4. 消息标记已读接口
**PUT /api/messages/{id}/read**
**功能描述**
:标记消息为已读
**请求参数**
:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| id | string | 是 | 消息ID |
**响应示例**
:
```
json
{
"code"
:
200
,
"message"
:
"success"
}
```
### 5. 模板卡片消息更新接口
**POST /api/messages/{id}/update_template_card**
**功能描述**
:更新模板卡片消息的替换文案信息(仅支持按钮交互型、投票选择型、多项选择型的卡片以及填写了action_menu字段的文本通知型、图文展示型)
**请求头**
:
```
Content-Type: application/json
Authorization: Bearer {app_token}
```
**请求参数**
:
| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| responseCode | string | 是 | 模板卡片消息返回的响应码 |
| templateCardData | object | 是 | 更新的模板卡片数据 |
**请求示例**
:
```
json
{
"responseCode"
:
"response_code_123456"
,
"templateCardData"
:
{
"taskId"
:
"task_123"
,
"title"
:
"审批任务状态更新"
,
"description"
:
"当前状态:已审批通过"
,
"button"
:
{
"text"
:
"查看详情"
,
"url"
:
"https://hr.company.com/approval/detail/123?status=approved"
}
}
}
```
**响应示例**
:
```
json
{
"code"
:
200
,
"message"
:
"success"
,
"data"
:
{
"updated"
:
true
,
"new_response_code"
:
"new_response_code_789012"
}
}
```
**注意事项**
:
-
仅当原卡片为按钮交互型、投票选择型、多项选择型的卡片以及填写了action_menu字段的文本通知型、图文展示型时可以调用本接口
-
response_code有效期为72小时,超过72小时后将无法使用
-
每次更新后会返回新的response_code,可用于后续更新
-
当用户点击任务卡片时,回调接口也会带上response_code
## 数据库设计
### 消息表结构
```
sql
CREATE
TABLE
messages
(
id
VARCHAR
(
50
)
PRIMARY
KEY
COMMENT
'消息ID'
,
app_id
VARCHAR
(
50
)
NOT
NULL
COMMENT
'应用ID'
,
user_id
VARCHAR
(
50
)
NOT
NULL
COMMENT
'用户ID'
,
title
VARCHAR
(
200
)
NOT
NULL
COMMENT
'消息标题'
,
content
TEXT
COMMENT
'消息内容'
,
target_url
VARCHAR
(
500
)
COMMENT
'跳转链接'
,
message_type
VARCHAR
(
30
)
COMMENT
'消息类型:text、image、voice、video、file、textcard、mpnews、markdown、miniprogram_notice、template_card'
,
msg_data
JSON
COMMENT
'消息扩展数据(JSON格式)'
,
response_code
VARCHAR
(
100
)
COMMENT
'模板卡片消息的响应码,用于后续更新'
,
response_code_expire_time
DATETIME
COMMENT
'响应码过期时间'
,
is_read
BOOLEAN
DEFAULT
FALSE
COMMENT
'是否已读'
,
create_time
DATETIME
COMMENT
'创建时间'
,
read_time
DATETIME
COMMENT
'读取时间'
,
INDEX
idx_user_id
(
user_id
),
INDEX
idx_create_time
(
create_time
),
INDEX
idx_app_id
(
app_id
),
INDEX
idx_message_type
(
message_type
),
INDEX
idx_response_code
(
response_code
)
)
ENGINE
=
InnoDB
DEFAULT
CHARSET
=
utf8mb4
COMMENT
=
'消息表'
;
```
### 应用配置表
```
sql
CREATE
TABLE
apps
(
app_id
VARCHAR
(
50
)
PRIMARY
KEY
COMMENT
'应用ID'
,
app_name
VARCHAR
(
100
)
NOT
NULL
COMMENT
'应用名称'
,
app_token
VARCHAR
(
100
)
NOT
NULL
COMMENT
'应用访问令牌'
,
status
BOOLEAN
DEFAULT
TRUE
COMMENT
'状态'
,
create_time
DATETIME
COMMENT
'创建时间'
,
update_time
DATETIME
COMMENT
'更新时间'
)
ENGINE
=
InnoDB
DEFAULT
CHARSET
=
utf8mb4
COMMENT
=
'应用配置表'
;
```
## 前端页面设计
### 1. 统一消息收件箱页面
-
**页面路径**
:
`/messages`
-
**功能说明**
:展示用户所有消息列表
-
**主要功能**
:
-
消息列表展示(按时间倒序)
-
消息已读/未读状态标识
-
点击消息跳转到对应应用
-
分页加载更多消息
### 2. 消息转发页面
-
**页面路径**
:
`/redirect?message_id={id}`
-
**功能说明**
:处理消息跳转逻辑
-
**处理流程**
:
1.
接收消息ID参数
2.
调用后端API获取跳转链接
3.
记录消息已读状态
4.
跳转到目标应用页面
## 安全设计
### 1. 应用认证
-
每个集成应用分配唯一的
`app_id`
和
`app_token`
-
应用调用API时需要携带
`Authorization`
头
-
后端验证应用身份和权限
### 2. 用户认证
-
复用现有内网应用的用户认证机制
-
通过企业微信获取用户ID进行身份验证
### 3. 数据安全
-
敏感数据传输使用HTTPS协议
-
数据库连接使用加密连接
-
定期备份重要数据
## 部署建议
### 1. 后端部署
-
建议使用Nginx作为反向代理
-
配置HTTPS证书
-
设置合理的超时时间
### 2. 数据库优化
-
为常用查询字段建立索引
-
定期清理过期消息数据
-
监控数据库性能
### 3. 监控告警
-
监控API调用成功率
-
监控消息推送延迟
-
设置异常告警机制
## 后续扩展
### 1. 功能扩展
-
支持消息分类和标签
-
添加消息搜索功能
-
支持批量操作
### 2. 性能优化
-
引入消息队列处理高并发
-
使用缓存提高查询性能
-
数据库读写分离
### 3. 统计分析
-
消息发送统计
-
用户行为分析
-
应用使用统计
## 不同类型消息处理说明
### 1. 文本消息(text)
-
最简单的消息类型
-
直接显示标题和内容
-
无需额外的msg_data数据
### 2. 文本卡片消息(textcard)
-
支持更丰富的展示效果
-
包含描述、跳转URL、按钮文字
-
适用于重要通知和待办事项
### 3. 图片消息(image)
-
需要包含图片URL和MD5值
-
前端可展示图片预览
-
支持点击查看大图
### 4. 文件消息(file)
-
包含文件名、文件URL、文件大小、文件类型
-
前端可显示文件图标和下载链接
-
支持直接下载或预览
### 5. Markdown消息(markdown)
src/main/java/com/metro/auth/platform/config/WebSecurityConfig.java
View file @
7b318c8d
...
...
@@ -104,7 +104,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
"/api/ps/account_sel/**"
,
"/znzl/file/**"
,
"/auth/v1/**"
,
"/auth/user/**"
,
"/error/**"
,
"/weixin/wxuserinfo/**"
,
"/weixin/information/**"
,
"/auth/dt/**"
,
"/avatar/**"
,
"/user/updateWxPlatformPersonnelByAccount"
,
"/wechatApi/**"
,
"/PlatformUserFavoriteAppsController/**"
,
"/roleuser/addUserNoticeRole"
"/PlatformUserFavoriteAppsController/**"
,
"/roleuser/addUserNoticeRole"
,
"/messagepush/**"
).
permitAll
()
.
antMatchers
(
HttpMethod
.
OPTIONS
,
"/**"
).
permitAll
()
// 除上面外的所有请求全部需要鉴权认证
...
...
src/main/java/com/metro/auth/platform/messagepush/config/WeChatConfig.java
0 → 100644
View file @
7b318c8d
package
com
.
metro
.
auth
.
platform
.
messagepush
.
config
;
import
lombok.Data
;
import
org.springframework.boot.context.properties.ConfigurationProperties
;
import
org.springframework.stereotype.Component
;
/**
* 企业微信内网应用配置属性
*/
@Data
@Component
@ConfigurationProperties
(
prefix
=
"weixin-params"
)
public
class
WeChatConfig
{
private
String
wxCorpId
;
private
String
wxAgentId
;
private
String
wxSecret
;
private
String
wxTxSecret
;
private
String
wxTokenUrl
;
private
String
wxSendMessageUrl
;
private
String
wxGetUserInfo
;
private
String
wxGetUserByCode
;
private
String
wxTxGetList
;
private
String
wxUserDeptDetail
;
}
src/main/java/com/metro/auth/platform/messagepush/controller/MessagePushController.java
0 → 100644
View file @
7b318c8d
package
com
.
metro
.
auth
.
platform
.
messagepush
.
controller
;
import
com.alibaba.fastjson.JSONObject
;
import
com.metro.auth.platform.domain.ResultCode
;
import
com.metro.auth.platform.domain.ResultJson
;
import
com.metro.auth.platform.messagepush.model.request.MessageSubmitRequest
;
import
com.metro.auth.platform.messagepush.service.MessagePushService
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.util.StringUtils
;
import
org.springframework.web.bind.annotation.*
;
import
javax.annotation.Resource
;
/**
* 企业微信内网应用消息推送控制器
*/
@Slf4j
@RestController
@RequestMapping
(
"/messagepush"
)
public
class
MessagePushController
{
@Resource
private
MessagePushService
messagePushService
;
/**
* 获取 AccessToken
* GET /messagepush/accesstoken
*/
@GetMapping
(
"/accesstoken"
)
public
ResultJson
getAccessToken
()
{
String
token
=
messagePushService
.
getAccessToken
();
if
(
StringUtils
.
hasLength
(
token
))
{
return
ResultJson
.
ok
(
token
);
}
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
"获取access_token失败"
);
}
/**
* 强制刷新 AccessToken
* GET /messagepush/accesstoken/refresh
*/
@GetMapping
(
"/accesstoken/refresh"
)
public
ResultJson
refreshAccessToken
()
{
String
token
=
messagePushService
.
refreshAccessToken
();
if
(
StringUtils
.
hasLength
(
token
))
{
return
ResultJson
.
ok
(
token
);
}
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
"刷新access_token失败"
);
}
/**
* 获取部门列表
* GET /messagepush/department/list?id=xxx
*/
@GetMapping
(
"/department/list"
)
public
ResultJson
getDepartmentList
(
@RequestParam
(
required
=
false
)
Integer
id
)
{
JSONObject
result
=
messagePushService
.
getDepartmentList
(
id
);
if
(
result
==
null
)
{
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
"调用企业微信API失败"
);
}
if
(
result
.
getInteger
(
"errcode"
)
!=
null
&&
result
.
getInteger
(
"errcode"
)
!=
0
)
{
log
.
error
(
"获取部门列表失败: {}"
,
result
.
toJSONString
());
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
result
.
getString
(
"errmsg"
));
}
return
ResultJson
.
ok
(
result
.
getJSONArray
(
"department"
));
}
/**
* 获取部门用户详情列表
* GET /messagepush/user/list?departmentId=1&fetchChild=1
*/
@GetMapping
(
"/user/list"
)
public
ResultJson
getUserList
(
@RequestParam
(
required
=
true
)
Integer
departmentId
,
@RequestParam
(
required
=
false
,
defaultValue
=
"1"
)
Integer
fetchChild
)
{
if
(
departmentId
==
null
)
{
return
ResultJson
.
failure
(
ResultCode
.
BAD_REQUEST
,
"departmentId不能为空"
);
}
JSONObject
result
=
messagePushService
.
getUserListByDepartment
(
departmentId
,
fetchChild
);
if
(
result
==
null
)
{
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
"调用企业微信API失败"
);
}
if
(
result
.
getInteger
(
"errcode"
)
!=
null
&&
result
.
getInteger
(
"errcode"
)
!=
0
)
{
log
.
error
(
"获取用户列表失败: {}"
,
result
.
toJSONString
());
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
result
.
getString
(
"errmsg"
));
}
return
ResultJson
.
ok
(
result
.
getJSONArray
(
"userlist"
));
}
/**
* 获取应用后台免登用户信息
* GET /messagepush/auth/getuserinfo?code=xxx
*/
@GetMapping
(
"/auth/getuserinfo"
)
public
ResultJson
getUserInfo
(
@RequestParam
(
required
=
true
)
String
code
)
{
if
(!
StringUtils
.
hasLength
(
code
))
{
return
ResultJson
.
failure
(
ResultCode
.
BAD_REQUEST
,
"code不能为空"
);
}
JSONObject
result
=
messagePushService
.
getUserInfoByCode
(
code
);
if
(
result
==
null
)
{
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
"调用企业微信API失败"
);
}
if
(
result
.
getInteger
(
"errcode"
)
!=
null
&&
result
.
getInteger
(
"errcode"
)
!=
0
)
{
log
.
error
(
"获取用户信息失败: {}"
,
result
.
toJSONString
());
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
result
.
getString
(
"errmsg"
));
}
return
ResultJson
.
ok
(
result
);
}
/**
* 根据 code 获取完整用户信息
* GET /messagepush/user/getuserinfo?code=xxx
*/
@GetMapping
(
"/user/getuserinfo"
)
public
ResultJson
getUserDetailByCode
(
@RequestParam
(
required
=
true
)
String
code
)
{
if
(!
StringUtils
.
hasLength
(
code
))
{
return
ResultJson
.
failure
(
ResultCode
.
BAD_REQUEST
,
"code不能为空"
);
}
JSONObject
result
=
messagePushService
.
getUserDetailByCode
(
code
);
if
(
result
==
null
)
{
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
"调用企业微信API失败"
);
}
if
(
result
.
getInteger
(
"errcode"
)
!=
null
&&
result
.
getInteger
(
"errcode"
)
!=
0
)
{
log
.
error
(
"获取用户详情失败: {}"
,
result
.
toJSONString
());
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
result
.
getString
(
"errmsg"
));
}
return
ResultJson
.
ok
(
result
);
}
/**
* 发送应用消息(JSON格式,透传)
* POST /messagepush/message/send
*/
@PostMapping
(
"/message/send"
)
public
ResultJson
sendMessage
(
@RequestBody
JSONObject
messageBody
)
{
if
(
messageBody
==
null
||
messageBody
.
isEmpty
())
{
return
ResultJson
.
failure
(
ResultCode
.
BAD_REQUEST
,
"消息内容不能为空"
);
}
log
.
info
(
"发送应用消息请求: {}"
,
messageBody
.
toJSONString
());
JSONObject
result
=
messagePushService
.
sendMessage
(
messageBody
.
toJSONString
());
if
(
result
==
null
)
{
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
"调用企业微信API失败"
);
}
if
(
result
.
getInteger
(
"errcode"
)
!=
null
&&
result
.
getInteger
(
"errcode"
)
!=
0
)
{
log
.
error
(
"发送消息失败: {}"
,
result
.
toJSONString
());
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
result
.
getString
(
"errmsg"
));
}
return
ResultJson
.
ok
(
result
);
}
/**
* 提交应用消息(实体类参数)
* POST /messagepush/message/submit
*/
@PostMapping
(
"/message/submit"
)
public
ResultJson
submitMessage
(
@RequestBody
MessageSubmitRequest
request
)
{
if
(
request
==
null
)
{
return
ResultJson
.
failure
(
ResultCode
.
BAD_REQUEST
,
"消息内容不能为空"
);
}
if
(!
StringUtils
.
hasLength
(
request
.
getUserId
()))
{
return
ResultJson
.
failure
(
ResultCode
.
BAD_REQUEST
,
"userId不能为空"
);
}
if
(!
StringUtils
.
hasLength
(
request
.
getMessageType
()))
{
return
ResultJson
.
failure
(
ResultCode
.
BAD_REQUEST
,
"messageType不能为空"
);
}
log
.
info
(
"提交应用消息请求: {}"
,
JSONObject
.
toJSONString
(
request
));
JSONObject
result
=
messagePushService
.
submitMessage
(
request
);
if
(
result
==
null
)
{
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
"调用企业微信API失败"
);
}
if
(
result
.
getInteger
(
"errcode"
)
!=
null
&&
result
.
getInteger
(
"errcode"
)
!=
0
)
{
log
.
error
(
"提交消息失败: {}"
,
result
.
toJSONString
());
return
ResultJson
.
failure
(
ResultCode
.
SERVER_ERROR
,
result
.
getString
(
"errmsg"
));
}
return
ResultJson
.
ok
(
result
);
}
}
src/main/java/com/metro/auth/platform/messagepush/model/request/MessageSubmitRequest.java
0 → 100644
View file @
7b318c8d
package
com
.
metro
.
auth
.
platform
.
messagepush
.
model
.
request
;
import
lombok.Data
;
/**
* 消息提交请求参数
*/
@Data
public
class
MessageSubmitRequest
{
/**
* 应用标识
*/
private
String
appId
;
/**
* 目标用户ID
*/
private
String
userId
;
/**
* 消息标题
*/
private
String
title
;
/**
* 消息内容
*/
private
String
content
;
/**
* 跳转链接
*/
private
String
targetUrl
;
/**
* 消息类型:text、textcard、markdown、image、file、news、mpnews、miniprogram_notice
*/
private
String
messageType
;
/**
* 时间戳,格式:YYYY-MM-DD HH:MM:SS
*/
private
String
timestamp
;
/**
* 特定消息类型的扩展数据
*/
private
Object
msgData
;
}
\ No newline at end of file
src/main/java/com/metro/auth/platform/messagepush/model/request/SendMessageRequest.java
0 → 100644
View file @
7b318c8d
package
com
.
metro
.
auth
.
platform
.
messagepush
.
model
.
request
;
import
lombok.Data
;
import
java.util.List
;
/**
* 发送应用消息请求参数
*/
@Data
public
class
SendMessageRequest
{
/**
* 接收人类型:user|party|tag
*/
private
String
touser
;
private
String
toparty
;
private
String
totag
;
/**
* 消息类型:text/textcard/markdown/image/file/news/mpnews/miniprogram_notice
*/
private
String
msgtype
;
/**
* 应用agentid
*/
private
Integer
agentid
;
/**
* 文本消息内容
*/
private
TextContent
text
;
/**
* 文本卡片消息内容
*/
private
TextCardContent
textcard
;
@Data
public
static
class
TextContent
{
private
String
content
;
}
@Data
public
static
class
TextCardContent
{
private
String
title
;
private
String
description
;
private
String
url
;
private
String
btntxt
;
}
}
src/main/java/com/metro/auth/platform/messagepush/model/request/UserListRequest.java
0 → 100644
View file @
7b318c8d
package
com
.
metro
.
auth
.
platform
.
messagepush
.
model
.
request
;
import
lombok.Data
;
/**
* 获取部门用户列表请求参数
*/
@Data
public
class
UserListRequest
{
/**
* 获取的部门id
*/
private
Integer
departmentId
;
/**
* 1/0:是否递归获取子部门下的用户
*/
private
Integer
fetchChild
=
1
;
}
src/main/java/com/metro/auth/platform/messagepush/model/response/WxDepartment.java
0 → 100644
View file @
7b318c8d
package
com
.
metro
.
auth
.
platform
.
messagepush
.
model
.
response
;
import
lombok.Data
;
/**
* 企业微信部门信息
*/
@Data
public
class
WxDepartment
{
/**
* 部门id
*/
private
Integer
id
;
/**
* 部门名称
*/
private
String
name
;
/**
* 父部门id
*/
private
Integer
parentid
;
/**
* 排序字段,值越小排序越靠前
*/
private
Integer
order
;
/**
* 部门层级
*/
private
Integer
level
;
/**
* 子部门数量
*/
private
Integer
childCount
;
}
src/main/java/com/metro/auth/platform/messagepush/model/response/WxMessageResult.java
0 → 100644
View file @
7b318c8d
package
com
.
metro
.
auth
.
platform
.
messagepush
.
model
.
response
;
import
lombok.Data
;
/**
* 企业微信消息发送结果
*/
@Data
public
class
WxMessageResult
{
/**
* 返回码,0表示成功
*/
private
Integer
errcode
;
/**
* 对返回码的文本描述
*/
private
String
errmsg
;
/**
* 消息id
*/
private
Long
msgid
;
/**
* 响应结果,0=成功
*/
private
Integer
responseType
;
/**
* 消息是否全部发送成功
*/
private
Boolean
invalidUser
;
/**
* 无效的partyid
*/
private
Boolean
invalidParty
;
/**
* 无效的tagid
*/
private
Boolean
invalidTag
;
}
src/main/java/com/metro/auth/platform/messagepush/model/response/WxUser.java
0 → 100644
View file @
7b318c8d
package
com
.
metro
.
auth
.
platform
.
messagepush
.
model
.
response
;
import
lombok.Data
;
/**
* 企业微信用户信息
*/
@Data
public
class
WxUser
{
/**
* 成员UserID
*/
private
String
userid
;
/**
* 成员名称
*/
private
String
name
;
/**
* 部门id列表
*/
private
Integer
[]
department
;
/**
* 职位信息
*/
private
String
position
;
/**
* 手机号
*/
private
String
mobile
;
/**
* 邮箱
*/
private
String
email
;
/**
* 头像url
*/
private
String
avatar
;
/**
* 性别。0表示未定义,1表示男性,2表示女性
*/
private
Integer
gender
;
/**
* 员工个人二维码,样式是一个小程序的二维码
*/
private
String
qrCode
;
/**
* 关注状态 1=已关注 2=禁用 4=未关注
*/
private
Integer
status
;
/**
* 是否是系统管理员
*/
private
Boolean
isleader
;
/**
* 成员备注
*/
private
String
remark
;
/**
* 激活状态 1=已激活 5=已退出
*/
private
Integer
enable
;
}
src/main/java/com/metro/auth/platform/messagepush/model/response/WxUserInfo.java
0 → 100644
View file @
7b318c8d
package
com
.
metro
.
auth
.
platform
.
messagepush
.
model
.
response
;
import
lombok.Data
;
/**
* 企业微信用户免登信息
*/
@Data
public
class
WxUserInfo
{
/**
* 成员UserID
*/
private
String
UserId
;
/**
* 成员DeviceId
*/
private
String
DeviceId
;
/**
* 只有手机和邮箱没有匹配时返回,扫码登录时会有此字段
*/
private
String
userTicket
;
/**
* userTicket的有效期(userTicket的有效期通过user_ticket获取用户信息时才会返回)
*/
private
Integer
expiresIn
;
}
src/main/java/com/metro/auth/platform/messagepush/service/MessagePushService.java
0 → 100644
View file @
7b318c8d
package
com
.
metro
.
auth
.
platform
.
messagepush
.
service
;
import
com.alibaba.fastjson.JSONObject
;
import
com.metro.auth.platform.messagepush.model.request.MessageSubmitRequest
;
/**
* 企业微信内网应用消息推送服务接口
*/
public
interface
MessagePushService
{
/**
* 获取 AccessToken
*/
String
getAccessToken
();
/**
* 强制刷新 AccessToken
*/
String
refreshAccessToken
();
/**
* 获取部门列表
*
* @param id 部门id,不传则获取全部
*/
JSONObject
getDepartmentList
(
Integer
id
);
/**
* 获取部门用户详情列表
*
* @param departmentId 部门id
* @param fetchChild 是否递归获取子部门(1=递归,0=不递归)
*/
JSONObject
getUserListByDepartment
(
Integer
departmentId
,
Integer
fetchChild
);
/**
* 获取应用后台免登用户信息(OAuth2)
*
* @param code 授权码
*/
JSONObject
getUserInfoByCode
(
String
code
);
/**
* 根据授权码获取完整用户信息
*
* @param code 授权码
*/
JSONObject
getUserDetailByCode
(
String
code
);
/**
* 发送应用消息
*
* @param messageJson 消息 JSON
*/
JSONObject
sendMessage
(
String
messageJson
);
/**
* 发送应用消息
*
* @param request 消息提交请求
*/
JSONObject
submitMessage
(
MessageSubmitRequest
request
);
}
src/main/java/com/metro/auth/platform/messagepush/service/impl/MessagePushServiceImpl.java
0 → 100644
View file @
7b318c8d
package
com
.
metro
.
auth
.
platform
.
messagepush
.
service
.
impl
;
import
com.alibaba.fastjson.JSONObject
;
import
com.metro.auth.platform.messagepush.model.request.MessageSubmitRequest
;
import
com.metro.auth.platform.messagepush.service.MessagePushService
;
import
com.metro.auth.platform.messagepush.util.WeChatApiUtil
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Service
;
import
javax.annotation.Resource
;
/**
* 企业微信内网应用消息推送服务实现
*/
@Slf4j
@Service
public
class
MessagePushServiceImpl
implements
MessagePushService
{
@Resource
private
WeChatApiUtil
weChatApiUtil
;
@Override
public
String
getAccessToken
()
{
return
weChatApiUtil
.
getAccessToken
();
}
@Override
public
String
refreshAccessToken
()
{
return
weChatApiUtil
.
refreshAccessToken
();
}
@Override
public
JSONObject
getDepartmentList
(
Integer
id
)
{
return
weChatApiUtil
.
getDepartmentList
(
id
);
}
@Override
public
JSONObject
getUserListByDepartment
(
Integer
departmentId
,
Integer
fetchChild
)
{
return
weChatApiUtil
.
getUserListByDepartment
(
departmentId
,
fetchChild
);
}
@Override
public
JSONObject
getUserInfoByCode
(
String
code
)
{
return
weChatApiUtil
.
getUserInfoByCode
(
code
);
}
@Override
public
JSONObject
getUserDetailByCode
(
String
code
)
{
return
weChatApiUtil
.
getUserDetailByCode
(
code
);
}
@Override
public
JSONObject
sendMessage
(
String
messageJson
)
{
return
weChatApiUtil
.
sendMessage
(
messageJson
);
}
@Override
public
JSONObject
submitMessage
(
MessageSubmitRequest
request
)
{
if
(
request
==
null
)
{
return
null
;
}
// 构建企业微信消息格式
JSONObject
message
=
new
JSONObject
();
message
.
put
(
"touser"
,
request
.
getUserId
());
message
.
put
(
"msgtype"
,
request
.
getMessageType
());
message
.
put
(
"agentid"
,
Integer
.
parseInt
(
weChatApiUtil
.
getWeChatConfig
().
getWxAgentId
()));
// 根据消息类型构建对应的消息体
switch
(
request
.
getMessageType
())
{
case
"text"
:
JSONObject
text
=
new
JSONObject
();
text
.
put
(
"content"
,
request
.
getContent
());
message
.
put
(
"text"
,
text
);
break
;
case
"textcard"
:
JSONObject
textcard
=
new
JSONObject
();
textcard
.
put
(
"title"
,
request
.
getTitle
());
textcard
.
put
(
"description"
,
request
.
getContent
());
textcard
.
put
(
"url"
,
request
.
getTargetUrl
());
// msg_data 可能包含 btntxt
if
(
request
.
getMsgData
()
!=
null
)
{
if
(
request
.
getMsgData
()
instanceof
JSONObject
)
{
JSONObject
msgData
=
(
JSONObject
)
request
.
getMsgData
();
if
(
msgData
.
containsKey
(
"btntxt"
))
{
textcard
.
put
(
"btntxt"
,
msgData
.
getString
(
"btntxt"
));
}
}
}
else
{
textcard
.
put
(
"btntxt"
,
"查看详情"
);
}
message
.
put
(
"textcard"
,
textcard
);
break
;
case
"markdown"
:
JSONObject
markdown
=
new
JSONObject
();
if
(
request
.
getMsgData
()
!=
null
&&
request
.
getMsgData
()
instanceof
JSONObject
)
{
markdown
.
putAll
((
JSONObject
)
request
.
getMsgData
());
}
message
.
put
(
"markdown"
,
markdown
);
break
;
case
"image"
:
JSONObject
image
=
new
JSONObject
();
if
(
request
.
getMsgData
()
!=
null
&&
request
.
getMsgData
()
instanceof
JSONObject
)
{
image
.
putAll
((
JSONObject
)
request
.
getMsgData
());
}
message
.
put
(
"image"
,
image
);
break
;
case
"file"
:
JSONObject
file
=
new
JSONObject
();
if
(
request
.
getMsgData
()
!=
null
&&
request
.
getMsgData
()
instanceof
JSONObject
)
{
file
.
putAll
((
JSONObject
)
request
.
getMsgData
());
}
message
.
put
(
"file"
,
file
);
break
;
case
"news"
:
case
"mpnews"
:
JSONObject
news
=
new
JSONObject
();
if
(
request
.
getMsgData
()
!=
null
&&
request
.
getMsgData
()
instanceof
JSONObject
)
{
news
.
putAll
((
JSONObject
)
request
.
getMsgData
());
}
message
.
put
(
request
.
getMessageType
(),
news
);
break
;
default
:
// 其他消息类型按通用格式处理
if
(
request
.
getMsgData
()
!=
null
&&
request
.
getMsgData
()
instanceof
JSONObject
)
{
message
.
put
(
request
.
getMessageType
(),
request
.
getMsgData
());
}
break
;
}
return
weChatApiUtil
.
sendMessage
(
message
.
toJSONString
());
}
}
src/main/java/com/metro/auth/platform/messagepush/util/WeChatApiUtil.java
0 → 100644
View file @
7b318c8d
package
com
.
metro
.
auth
.
platform
.
messagepush
.
util
;
import
com.alibaba.fastjson.JSONObject
;
import
com.metro.auth.platform.http.HttpAPIService
;
import
com.metro.auth.platform.messagepush.config.WeChatConfig
;
import
com.metro.auth.platform.redis.RedisUtils
;
import
com.metro.auth.platform.wxmessage.ApiConfig
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.stereotype.Component
;
import
org.springframework.util.StringUtils
;
import
javax.annotation.Resource
;
import
java.util.concurrent.TimeUnit
;
/**
* 企业微信内网应用 API 调用工具类
*/
@Slf4j
@Component
public
class
WeChatApiUtil
{
private
static
final
String
ACCESS_TOKEN_KEY
=
"wechat:access_token"
;
private
static
final
long
ACCESS_TOKEN_EXPIRE
=
7100L
;
@Resource
private
WeChatConfig
weChatConfig
;
@Resource
private
HttpAPIService
httpAPIService
;
@Resource
private
RedisUtils
redisUtils
;
/**
* 获取 AccessToken(优先从 Redis 缓存获取)
*/
public
String
getAccessToken
()
{
Object
cached
=
redisUtils
.
get
(
ACCESS_TOKEN_KEY
);
if
(
cached
!=
null
&&
StringUtils
.
hasLength
(
cached
.
toString
()))
{
log
.
debug
(
"从Redis缓存获取access_token"
);
return
cached
.
toString
();
}
log
.
debug
(
"Redis缓存未命中,从API获取access_token"
);
return
refreshAccessToken
();
}
/**
* 强制刷新 AccessToken
*/
public
String
refreshAccessToken
()
{
String
url
=
weChatConfig
.
getWxTokenUrl
()
+
"?corpid="
+
weChatConfig
.
getWxCorpId
()
+
"&corpsecret="
+
weChatConfig
.
getWxSecret
();
try
{
String
result
=
httpAPIService
.
doGet
(
url
);
if
(
result
!=
null
)
{
JSONObject
json
=
JSONObject
.
parseObject
(
result
);
String
token
=
json
.
getString
(
"access_token"
);
Integer
expiresIn
=
json
.
getInteger
(
"expires_in"
);
if
(
StringUtils
.
hasLength
(
token
))
{
redisUtils
.
set
(
ACCESS_TOKEN_KEY
,
token
,
expiresIn
!=
null
?
expiresIn
:
ACCESS_TOKEN_EXPIRE
,
TimeUnit
.
SECONDS
);
log
.
info
(
"access_token刷新成功: {}"
,
token
);
return
token
;
}
}
}
catch
(
Exception
e
)
{
log
.
error
(
"刷新access_token失败"
,
e
);
}
return
null
;
}
/**
* 获取部门列表
*
* @param id 部门id,不传则获取全部
*/
public
JSONObject
getDepartmentList
(
Integer
id
)
{
String
token
=
getAccessToken
();
String
url
=
weChatConfig
.
getWxTxGetList
()
+
token
;
if
(
id
!=
null
)
{
url
+=
"&id="
+
id
;
}
String
result
=
httpAPIService
.
doGet
(
url
);
return
result
!=
null
?
JSONObject
.
parseObject
(
result
)
:
null
;
}
/**
* 获取部门用户详情列表
*
* @param departmentId 部门id
* @param fetchChild 是否递归获取子部门
*/
public
JSONObject
getUserListByDepartment
(
Integer
departmentId
,
Integer
fetchChild
)
{
if
(
departmentId
==
null
)
{
return
null
;
}
String
token
=
getAccessToken
();
String
url
=
weChatConfig
.
getWxUserDeptDetail
()
+
token
+
"&department_id="
+
departmentId
+
"&fetch_child="
+
(
fetchChild
!=
null
?
fetchChild
:
1
);
String
result
=
httpAPIService
.
doGet
(
url
);
return
result
!=
null
?
JSONObject
.
parseObject
(
result
)
:
null
;
}
/**
* 获取应用后台免登用户信息(OAuth2 授权码)
*
* @param code OAuth2 授权码
*/
public
JSONObject
getUserInfoByCode
(
String
code
)
{
if
(!
StringUtils
.
hasLength
(
code
))
{
return
null
;
}
String
token
=
getAccessToken
();
String
url
=
weChatConfig
.
getWxGetUserInfo
()
+
token
+
"&code="
+
code
;
String
result
=
httpAPIService
.
doGet
(
url
);
return
result
!=
null
?
JSONObject
.
parseObject
(
result
)
:
null
;
}
/**
* 根据 code 获取完整用户信息
*
* @param code OAuth2 授权码
*/
public
JSONObject
getUserDetailByCode
(
String
code
)
{
if
(!
StringUtils
.
hasLength
(
code
))
{
return
null
;
}
String
token
=
getAccessToken
();
String
url
=
weChatConfig
.
getWxGetUserByCode
()
+
token
+
"&code="
+
code
;
String
result
=
httpAPIService
.
doGet
(
url
);
return
result
!=
null
?
JSONObject
.
parseObject
(
result
)
:
null
;
}
/**
* 发送应用消息
*
* @param messageJson 消息 JSON
*/
public
JSONObject
sendMessage
(
String
messageJson
)
{
String
token
=
getAccessToken
();
String
url
=
weChatConfig
.
getWxSendMessageUrl
()
+
token
;
return
httpAPIService
.
doPost
(
url
,
messageJson
);
}
public
WeChatConfig
getWeChatConfig
()
{
return
weChatConfig
;
}
}
src/main/resources/application-dev.yml
View file @
7b318c8d
...
...
@@ -182,6 +182,7 @@ weixin-params:
wx_token_url
:
https://qyapi.weixin.qq.com/cgi-bin/gettoken
wx_jstiket
:
https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=
wx_getuserinfo
:
https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=
wx_getuser_bycode
:
https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo_bycode?access_token=
wx_all_userinfo
:
https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=
#微信通讯录管理
#获取通讯录管理secret
...
...
src/main/resources/application-prod.yml
View file @
7b318c8d
...
...
@@ -185,6 +185,7 @@ weixin-params:
wx_token_url
:
https://qyapi.weixin.qq.com/cgi-bin/gettoken
wx_jstiket
:
https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=
wx_getuserinfo
:
https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=
wx_getuser_bycode
:
https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo_bycode?access_token=
wx_all_userinfo
:
https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=
#微信通讯录管理
#获取通讯录管理secret
...
...
src/main/resources/application-sjt.yml
View file @
7b318c8d
...
...
@@ -159,6 +159,7 @@ weixin-params:
wx_token_url
:
https://qyapi.weixin.qq.com/cgi-bin/gettoken
wx_jstiket
:
https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=
wx_getuserinfo
:
https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=
wx_getuser_bycode
:
https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo_bycode?access_token=
wx_all_userinfo
:
https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=
#微信通讯录管理
#获取通讯录管理secret
...
...
src/main/resources/application-test151.yml
View file @
7b318c8d
...
...
@@ -183,6 +183,7 @@ weixin-params:
wx_token_url
:
https://qyapi.weixin.qq.com/cgi-bin/gettoken
wx_jstiket
:
https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=
wx_getuserinfo
:
https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=
wx_getuser_bycode
:
https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo_bycode?access_token=
wx_all_userinfo
:
https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=
#微信通讯录管理
#获取通讯录管理secret
...
...
src/main/resources/application-test153.yml
View file @
7b318c8d
...
...
@@ -185,6 +185,7 @@ weixin-params:
wx_token_url
:
https://qyapi.weixin.qq.com/cgi-bin/gettoken
wx_jstiket
:
https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=
wx_getuserinfo
:
https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=
wx_getuser_bycode
:
https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo_bycode?access_token=
wx_all_userinfo
:
https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=
#微信通讯录管理
#获取通讯录管理secret
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论