feat: 集成阿里云 IMM (即时媒体服务) 与 OSS 跨域配置优化
主要变更: - 新增阿里云 IMM SDK 依赖 (imm20200930 v1.28.3) - 新增 IMM 配置类 (ImmConfig, ImmUtil, ImmController, ImmTokenVo) - 新增前端 API 生成文件 (imm.api.ts) - 更新 WebOffice.vue 使用新的 imm.api 导入 配置优化: - 三环境 (dev/test/prod) 均开启 OSS CORS 跨域支持 - 添加 IMM 服务配置 (endpoint, region, project, 密钥) - 测试/开发环境跨域域名设置为通配符 技术栈: - 后端:Spring Boot + 阿里云 IMM SDK - 前端:Vue 3 + TypeScript API 生成 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
709e59e142
commit
ce7ee34666
@ -0,0 +1,121 @@
|
|||||||
|
# Page snapshot
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- generic [ref=e3]:
|
||||||
|
- complementary [ref=e4]:
|
||||||
|
- generic [ref=e5]:
|
||||||
|
- generic [ref=e6]:
|
||||||
|
- img "Logo" [ref=e7]
|
||||||
|
- generic [ref=e8]:
|
||||||
|
- generic [ref=e9]: 少儿智慧阅读
|
||||||
|
- generic [ref=e10]: 服务管理后台
|
||||||
|
- menu [ref=e12]:
|
||||||
|
- menuitem "数据看板" [ref=e13] [cursor=pointer]:
|
||||||
|
- img [ref=e14]
|
||||||
|
- generic [ref=e20]: 数据看板
|
||||||
|
- menuitem "课程包管理" [ref=e21] [cursor=pointer]:
|
||||||
|
- img [ref=e22]
|
||||||
|
- generic [ref=e25]: 课程包管理
|
||||||
|
- menuitem "database 套餐管理" [ref=e26] [cursor=pointer]:
|
||||||
|
- img "database" [ref=e27]:
|
||||||
|
- img [ref=e28]
|
||||||
|
- generic [ref=e31]: 套餐管理
|
||||||
|
- menuitem "format-painter 主题字典" [ref=e32] [cursor=pointer]:
|
||||||
|
- img "format-painter" [ref=e33]:
|
||||||
|
- img [ref=e34]
|
||||||
|
- generic [ref=e37]: 主题字典
|
||||||
|
- menuitem "租户管理" [ref=e38] [cursor=pointer]:
|
||||||
|
- img [ref=e39]
|
||||||
|
- generic [ref=e44]: 租户管理
|
||||||
|
- menuitem "资源库" [ref=e45] [cursor=pointer]:
|
||||||
|
- img [ref=e46]
|
||||||
|
- generic [ref=e49]: 资源库
|
||||||
|
- menuitem "系统设置" [ref=e50] [cursor=pointer]:
|
||||||
|
- img [ref=e51]
|
||||||
|
- generic [ref=e55]: 系统设置
|
||||||
|
- generic [ref=e56]:
|
||||||
|
- generic [ref=e57]:
|
||||||
|
- img "menu-fold" [ref=e59] [cursor=pointer]:
|
||||||
|
- img [ref=e60]
|
||||||
|
- generic [ref=e63]:
|
||||||
|
- generic [ref=e65]:
|
||||||
|
- img "bell" [ref=e66] [cursor=pointer]:
|
||||||
|
- img [ref=e67]
|
||||||
|
- superscript [ref=e69]:
|
||||||
|
- paragraph [ref=e71]: "5"
|
||||||
|
- generic [ref=e73] [cursor=pointer]:
|
||||||
|
- img "user" [ref=e76]:
|
||||||
|
- img [ref=e77]
|
||||||
|
- generic [ref=e79]: 系统管理员
|
||||||
|
- img "down" [ref=e81]:
|
||||||
|
- img [ref=e82]
|
||||||
|
- main [ref=e84]:
|
||||||
|
- generic [ref=e85]:
|
||||||
|
- generic [ref=e87]:
|
||||||
|
- generic [ref=e88]:
|
||||||
|
- button "返回" [ref=e90] [cursor=pointer]:
|
||||||
|
- img "arrow-left" [ref=e91]:
|
||||||
|
- img [ref=e92]
|
||||||
|
- generic "编辑课程包" [ref=e94]
|
||||||
|
- generic [ref=e98]:
|
||||||
|
- button "保存草稿" [ref=e100] [cursor=pointer]:
|
||||||
|
- generic [ref=e101]: 保存草稿
|
||||||
|
- button "保 存" [ref=e103] [cursor=pointer]:
|
||||||
|
- generic [ref=e104]: 保 存
|
||||||
|
- generic [ref=e108]:
|
||||||
|
- generic [ref=e109]:
|
||||||
|
- button "check 基本信息" [ref=e111] [cursor=pointer]:
|
||||||
|
- img "check" [ref=e114]:
|
||||||
|
- img [ref=e115]
|
||||||
|
- generic [ref=e118]: 基本信息
|
||||||
|
- button "check 课程介绍" [ref=e120] [cursor=pointer]:
|
||||||
|
- img "check" [ref=e123]:
|
||||||
|
- img [ref=e124]
|
||||||
|
- generic [ref=e127]: 课程介绍
|
||||||
|
- button "check 排课参考" [ref=e129] [cursor=pointer]:
|
||||||
|
- img "check" [ref=e132]:
|
||||||
|
- img [ref=e133]
|
||||||
|
- generic [ref=e136]: 排课参考
|
||||||
|
- button "check 导入课" [ref=e138] [cursor=pointer]:
|
||||||
|
- img "check" [ref=e141]:
|
||||||
|
- img [ref=e142]
|
||||||
|
- generic [ref=e145]: 导入课
|
||||||
|
- button "check 集体课" [ref=e147] [cursor=pointer]:
|
||||||
|
- img "check" [ref=e150]:
|
||||||
|
- img [ref=e151]
|
||||||
|
- generic [ref=e154]: 集体课
|
||||||
|
- button "check 领域课" [ref=e156] [cursor=pointer]:
|
||||||
|
- img "check" [ref=e159]:
|
||||||
|
- img [ref=e160]
|
||||||
|
- generic [ref=e163]: 领域课
|
||||||
|
- button "7 环创建设" [ref=e165]:
|
||||||
|
- generic [ref=e166]: "7"
|
||||||
|
- generic [ref=e168]: 环创建设
|
||||||
|
- generic [ref=e169]:
|
||||||
|
- generic [ref=e170]: 完成度
|
||||||
|
- progressbar [ref=e171]:
|
||||||
|
- img "check-circle" [ref=e176]:
|
||||||
|
- img [ref=e177]
|
||||||
|
- generic [ref=e179]:
|
||||||
|
- text: "* : * : * : : * : 26 / 200 : : : 60 / 1500 64 / 1500 71 / 1500 61 / 1500 33 / 1500 35 / 1500 33 / 1500 36 / 1500 : : : 0 / 500 : : : * : 94 / 1500 * : 64 / 1500 : 0 / 1500 : 0 / 1500 : 0 / 1500 : : : 0 / 500 : : : * : 0 / 1500 * : 0 / 1500 : 0 / 1500 : 0 / 1500 : 0 / 1500 : : : 0 / 500 : : : * : 64 / 1500 * : 0 / 1500 : 0 / 1500 : 0 / 1500 : 0 / 1500 : : : 0 / 500 : : : * : 68 / 1500 * : 0 / 1500 : 0 / 1500 : 0 / 1500 : 0 / 1500"
|
||||||
|
- generic [ref=e180]:
|
||||||
|
- generic [ref=e181]:
|
||||||
|
- generic [ref=e182]: 环创建设
|
||||||
|
- generic [ref=e183]: 已填写
|
||||||
|
- alert [ref=e185]:
|
||||||
|
- img "info-circle" [ref=e186]:
|
||||||
|
- img [ref=e187]
|
||||||
|
- generic [ref=e190]:
|
||||||
|
- generic [ref=e191]: 填写提示
|
||||||
|
- generic [ref=e192]: 环创建设内容可包括:主题环境布置、区域活动环境、阅读角创设、材料投放建议等,帮助教师更好地创设支持幼儿学习的环境。
|
||||||
|
- generic [ref=e194]:
|
||||||
|
- textbox "请输入环创建设内容,例如: - 主题墙布置建议 - 阅读区环境创设 - 材料展示区设置 - 互动区域规划 - 相关装饰物品建议等" [ref=e195]:
|
||||||
|
- /placeholder: "请输入环创建设内容,例如:\r\n- 主题墙布置建议\r\n- 阅读区环境创设\r\n- 材料展示区设置\r\n- 互动区域规划\r\n- 相关装饰物品建议等"
|
||||||
|
- text: 1. 夸夸卡展示区:展示幼儿制作的夸夸卡 2. "我的特别之处"展示墙:张贴幼儿分享的特别之处作品 3. 兔子探秘墙:张贴兔子图片和观察记录 4. 音乐角环创:张贴儿歌歌词图谱、兔子头饰 5. 健康小卫士展示区:张贴保护耳朵方法海报
|
||||||
|
- text: 116 / 3000
|
||||||
|
- generic [ref=e196]:
|
||||||
|
- button "上一步" [ref=e197] [cursor=pointer]:
|
||||||
|
- generic [ref=e198]: 上一步
|
||||||
|
- button "保 存" [active] [ref=e199] [cursor=pointer]:
|
||||||
|
- generic [ref=e200]: 保 存
|
||||||
|
```
|
||||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v8.5.3 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* Reading Platform API
|
||||||
|
* Reading Platform Backend Service API Documentation
|
||||||
|
* OpenAPI spec version: 1.0.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课程环节响应
|
||||||
|
*/
|
||||||
|
export interface CourseLessonResponse {
|
||||||
|
/** ID */
|
||||||
|
id?: number;
|
||||||
|
/** 课程 ID */
|
||||||
|
courseId?: number;
|
||||||
|
/** 课程类型 */
|
||||||
|
lessonType?: string;
|
||||||
|
/** 名称 */
|
||||||
|
name?: string;
|
||||||
|
/** 描述 */
|
||||||
|
description?: string;
|
||||||
|
/** 时长(分钟) */
|
||||||
|
duration?: number;
|
||||||
|
/** 视频路径 */
|
||||||
|
videoPath?: string;
|
||||||
|
/** 视频名称 */
|
||||||
|
videoName?: string;
|
||||||
|
/** PPT 路径 */
|
||||||
|
pptPath?: string;
|
||||||
|
/** PPT 名称 */
|
||||||
|
pptName?: string;
|
||||||
|
/** PDF 路径 */
|
||||||
|
pdfPath?: string;
|
||||||
|
/** PDF 名称 */
|
||||||
|
pdfName?: string;
|
||||||
|
/** 教学目标 */
|
||||||
|
objectives?: string;
|
||||||
|
/** 教学准备 */
|
||||||
|
preparation?: string;
|
||||||
|
/** 教学延伸 */
|
||||||
|
extension?: string;
|
||||||
|
/** 教学反思 */
|
||||||
|
reflection?: string;
|
||||||
|
/** 评估数据 */
|
||||||
|
assessmentData?: string;
|
||||||
|
/** 是否使用模板 */
|
||||||
|
useTemplate?: boolean;
|
||||||
|
/** 排序号 */
|
||||||
|
sortOrder?: number;
|
||||||
|
/** 创建时间 */
|
||||||
|
createdAt?: string;
|
||||||
|
/** 更新时间 */
|
||||||
|
updatedAt?: string;
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v8.5.3 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* Reading Platform API
|
||||||
|
* Reading Platform Backend Service API Documentation
|
||||||
|
* OpenAPI spec version: 1.0.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课程包中的课程项
|
||||||
|
*/
|
||||||
|
export interface CoursePackageCourseItem {
|
||||||
|
/** 课程 ID */
|
||||||
|
id?: number;
|
||||||
|
/** 课程名称 */
|
||||||
|
name?: string;
|
||||||
|
/** 适用年级 */
|
||||||
|
gradeLevel?: string;
|
||||||
|
/** 排序号 */
|
||||||
|
sortOrder?: number;
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v8.5.3 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* Reading Platform API
|
||||||
|
* Reading Platform Backend Service API Documentation
|
||||||
|
* OpenAPI spec version: 1.0.0
|
||||||
|
*/
|
||||||
|
import type { CoursePackageCourseItem } from './coursePackageCourseItem';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 课程套餐响应
|
||||||
|
*/
|
||||||
|
export interface CoursePackageResponse {
|
||||||
|
/** ID */
|
||||||
|
id?: number;
|
||||||
|
/** 名称 */
|
||||||
|
name?: string;
|
||||||
|
/** 描述 */
|
||||||
|
description?: string;
|
||||||
|
/** 价格(分) */
|
||||||
|
price?: number;
|
||||||
|
/** 折后价格(分) */
|
||||||
|
discountPrice?: number;
|
||||||
|
/** 折扣类型 */
|
||||||
|
discountType?: string;
|
||||||
|
/** 年级水平(数组) */
|
||||||
|
gradeLevels?: string[];
|
||||||
|
/** 课程数量 */
|
||||||
|
courseCount?: number;
|
||||||
|
/** 使用学校数 */
|
||||||
|
tenantCount?: number;
|
||||||
|
/** 状态 */
|
||||||
|
status?: string;
|
||||||
|
/** 提交时间 */
|
||||||
|
submittedAt?: string;
|
||||||
|
/** 提交人 ID */
|
||||||
|
submittedBy?: number;
|
||||||
|
/** 审核时间 */
|
||||||
|
reviewedAt?: string;
|
||||||
|
/** 审核人 ID */
|
||||||
|
reviewedBy?: number;
|
||||||
|
/** 审核意见 */
|
||||||
|
reviewComment?: string;
|
||||||
|
/** 发布时间 */
|
||||||
|
publishedAt?: string;
|
||||||
|
/** 创建时间 */
|
||||||
|
createdAt?: string;
|
||||||
|
/** 更新时间 */
|
||||||
|
updatedAt?: string;
|
||||||
|
/** 包含的课程 */
|
||||||
|
courses?: CoursePackageCourseItem[];
|
||||||
|
/** 开始日期(租户套餐) */
|
||||||
|
startDate?: string;
|
||||||
|
/** 结束日期(租户套餐) */
|
||||||
|
endDate?: string;
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v8.5.3 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* Reading Platform API
|
||||||
|
* Reading Platform Backend Service API Documentation
|
||||||
|
* OpenAPI spec version: 1.0.0
|
||||||
|
*/
|
||||||
|
import type { CoursePackageResponse } from './coursePackageResponse';
|
||||||
|
|
||||||
|
export interface PageResultCoursePackageResponse {
|
||||||
|
list?: CoursePackageResponse[];
|
||||||
|
total?: number;
|
||||||
|
pageNum?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
pages?: number;
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v8.5.3 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* Reading Platform API
|
||||||
|
* Reading Platform Backend Service API Documentation
|
||||||
|
* OpenAPI spec version: 1.0.0
|
||||||
|
*/
|
||||||
|
import type { ResourceItem } from './resourceItem';
|
||||||
|
|
||||||
|
export interface PageResultResourceItem {
|
||||||
|
list?: ResourceItem[];
|
||||||
|
total?: number;
|
||||||
|
pageNum?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
pages?: number;
|
||||||
|
}
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v8.5.3 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* Reading Platform API
|
||||||
|
* Reading Platform Backend Service API Documentation
|
||||||
|
* OpenAPI spec version: 1.0.0
|
||||||
|
*/
|
||||||
|
import type { ResourceLibrary } from './resourceLibrary';
|
||||||
|
|
||||||
|
export interface PageResultResourceLibrary {
|
||||||
|
list?: ResourceLibrary[];
|
||||||
|
total?: number;
|
||||||
|
pageNum?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
pages?: number;
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v8.5.3 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* Reading Platform API
|
||||||
|
* Reading Platform Backend Service API Documentation
|
||||||
|
* OpenAPI spec version: 1.0.0
|
||||||
|
*/
|
||||||
|
import type { CoursePackageResponse } from './coursePackageResponse';
|
||||||
|
|
||||||
|
export interface ResultCoursePackageResponse {
|
||||||
|
code?: number;
|
||||||
|
message?: string;
|
||||||
|
data?: CoursePackageResponse;
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v8.5.3 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* Reading Platform API
|
||||||
|
* Reading Platform Backend Service API Documentation
|
||||||
|
* OpenAPI spec version: 1.0.0
|
||||||
|
*/
|
||||||
|
import type { CoursePackageResponse } from './coursePackageResponse';
|
||||||
|
|
||||||
|
export interface ResultListCoursePackageResponse {
|
||||||
|
code?: number;
|
||||||
|
message?: string;
|
||||||
|
data?: CoursePackageResponse[];
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v8.5.3 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* Reading Platform API
|
||||||
|
* Reading Platform Backend Service API Documentation
|
||||||
|
* OpenAPI spec version: 1.0.0
|
||||||
|
*/
|
||||||
|
import type { PageResultCoursePackageResponse } from './pageResultCoursePackageResponse';
|
||||||
|
|
||||||
|
export interface ResultPageResultCoursePackageResponse {
|
||||||
|
code?: number;
|
||||||
|
message?: string;
|
||||||
|
data?: PageResultCoursePackageResponse;
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v8.5.3 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* Reading Platform API
|
||||||
|
* Reading Platform Backend Service API Documentation
|
||||||
|
* OpenAPI spec version: 1.0.0
|
||||||
|
*/
|
||||||
|
import type { PageResultResourceItem } from './pageResultResourceItem';
|
||||||
|
|
||||||
|
export interface ResultPageResultResourceItem {
|
||||||
|
code?: number;
|
||||||
|
message?: string;
|
||||||
|
data?: PageResultResourceItem;
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* Generated by orval v8.5.3 🍺
|
||||||
|
* Do not edit manually.
|
||||||
|
* Reading Platform API
|
||||||
|
* Reading Platform Backend Service API Documentation
|
||||||
|
* OpenAPI spec version: 1.0.0
|
||||||
|
*/
|
||||||
|
import type { PageResultResourceLibrary } from './pageResultResourceLibrary';
|
||||||
|
|
||||||
|
export interface ResultPageResultResourceLibrary {
|
||||||
|
code?: number;
|
||||||
|
message?: string;
|
||||||
|
data?: PageResultResourceLibrary;
|
||||||
|
}
|
||||||
36
reading-platform-frontend/src/api/imm.api.ts
Normal file
36
reading-platform-frontend/src/api/imm.api.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* 阿里云 IMM WebOffice API
|
||||||
|
* 用于文档在线预览和编辑
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { http } from '@/api';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成只读 WebOffice Token
|
||||||
|
* @param url OSS 文件路径(如:oss://bucket-name/path/to/file.pptx 或完整 HTTPS URL)
|
||||||
|
* @param name 文件名
|
||||||
|
* @returns Token 信息
|
||||||
|
*/
|
||||||
|
export function generateWebofficeTokenReadOnly(params: { url: string; name: string }) {
|
||||||
|
return http.get('/v1/imm/token/readonly', { params });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成编辑 WebOffice Token
|
||||||
|
* @param url OSS 文件路径(如:oss://bucket-name/path/to/file.pptx 或完整 HTTPS URL)
|
||||||
|
* @param name 文件名
|
||||||
|
* @returns Token 信息
|
||||||
|
*/
|
||||||
|
export function generateWebofficeToken(params: { url: string; name: string }) {
|
||||||
|
return http.get('/v1/imm/token', { params });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新 WebOffice Token
|
||||||
|
* @param accessToken 当前访问凭证
|
||||||
|
* @param refreshToken 刷新凭证
|
||||||
|
* @returns 刷新后的 Token 信息
|
||||||
|
*/
|
||||||
|
export function refreshWebofficeToken(data: { accessToken: string; refreshToken: string }) {
|
||||||
|
return http.post('/v1/imm/token/refresh', data);
|
||||||
|
}
|
||||||
@ -46,7 +46,7 @@ import {
|
|||||||
generateWebofficeToken,
|
generateWebofficeToken,
|
||||||
generateWebofficeTokenReadOnly,
|
generateWebofficeTokenReadOnly,
|
||||||
refreshWebofficeToken,
|
refreshWebofficeToken,
|
||||||
} from '@/views/cms/teaching-material/CmsTeachingMaterial.api';
|
} from '@/api/imm.api';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
// import { usePermission } from '@/hooks/web/usePermission';
|
// import { usePermission } from '@/hooks/web/usePermission';
|
||||||
// import { insertPPTImage, insertWordImage } from './webOffice';
|
// import { insertPPTImage, insertWordImage } from './webOffice';
|
||||||
|
|||||||
@ -149,6 +149,12 @@
|
|||||||
<artifactId>aliyun-sdk-oss</artifactId>
|
<artifactId>aliyun-sdk-oss</artifactId>
|
||||||
<version>3.17.1</version>
|
<version>3.17.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- Aliyun IMM SDK -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.aliyun</groupId>
|
||||||
|
<artifactId>imm20200930</artifactId>
|
||||||
|
<version>1.28.3</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba.fastjson2</groupId>
|
<groupId>com.alibaba.fastjson2</groupId>
|
||||||
<artifactId>fastjson2-extension-spring6</artifactId>
|
<artifactId>fastjson2-extension-spring6</artifactId>
|
||||||
|
|||||||
@ -0,0 +1,42 @@
|
|||||||
|
package com.reading.platform.common.config;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 阿里云 IMM(智能媒体服务)配置类
|
||||||
|
*
|
||||||
|
* @author reading-platform
|
||||||
|
* @since 2026-03-16
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "aliyun.imm")
|
||||||
|
public class ImmConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IMM 服务终端节点(如:imm-cn-shanghai.aliyuncs.com)
|
||||||
|
*/
|
||||||
|
private String endpoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务区域(如:cn-shanghai)
|
||||||
|
*/
|
||||||
|
private String region;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问密钥 ID
|
||||||
|
*/
|
||||||
|
private String accessKeyId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问密钥秘密
|
||||||
|
*/
|
||||||
|
private String accessKeySecret;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IMM 项目名称
|
||||||
|
*/
|
||||||
|
private String projectName;
|
||||||
|
}
|
||||||
@ -0,0 +1,241 @@
|
|||||||
|
package com.reading.platform.common.util;
|
||||||
|
|
||||||
|
import com.aliyun.imm20200930.Client;
|
||||||
|
import com.aliyun.imm20200930.models.*;
|
||||||
|
import com.reading.platform.common.config.ImmConfig;
|
||||||
|
import com.reading.platform.dto.response.ImmTokenVo;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 阿里云 IMM(智能媒体服务)工具类
|
||||||
|
* <p>
|
||||||
|
* 封装 WebOffice Token 生成、刷新等操作
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author reading-platform
|
||||||
|
* @since 2026-03-16
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class ImmUtil {
|
||||||
|
|
||||||
|
private final ImmConfig immConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成 WebOffice Token(只读权限)
|
||||||
|
*
|
||||||
|
* @param sourceURI OSS 文件路径(如:oss://bucket-name/path/to/file.pptx)
|
||||||
|
* @param name 文件名
|
||||||
|
* @return WebOffice Token 信息
|
||||||
|
*/
|
||||||
|
public ImmTokenVo generateWebofficeTokenReadOnly(String sourceURI, String name) {
|
||||||
|
return generateWebofficeToken(sourceURI, name, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成 WebOffice Token(编辑权限)
|
||||||
|
*
|
||||||
|
* @param sourceURI OSS 文件路径(如:oss://bucket-name/path/to/file.pptx)
|
||||||
|
* @param name 文件名
|
||||||
|
* @return WebOffice Token 信息
|
||||||
|
*/
|
||||||
|
public ImmTokenVo generateWebofficeToken(String sourceURI, String name) {
|
||||||
|
return generateWebofficeToken(sourceURI, name, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成 WebOffice Token
|
||||||
|
*
|
||||||
|
* @param sourceURI OSS 文件路径(如:oss://bucket-name/path/to/file.pptx)
|
||||||
|
* @param name 文件名
|
||||||
|
* @param isReadOnly 是否只读
|
||||||
|
* @return WebOffice Token 信息
|
||||||
|
*/
|
||||||
|
private ImmTokenVo generateWebofficeToken(String sourceURI, String name, boolean isReadOnly) {
|
||||||
|
try {
|
||||||
|
log.info("生成 WebOffice Token: sourceURI={}, name={}, isReadOnly={}", sourceURI, name, isReadOnly);
|
||||||
|
|
||||||
|
// 获取 IMM 客户端
|
||||||
|
Client client = getImmClient();
|
||||||
|
|
||||||
|
// 构建权限配置
|
||||||
|
WebofficePermission permission = new WebofficePermission()
|
||||||
|
.setReadonly(isReadOnly)
|
||||||
|
.setCopy(!isReadOnly)
|
||||||
|
.setExport(!isReadOnly)
|
||||||
|
.setPrint(!isReadOnly)
|
||||||
|
.setHistory(!isReadOnly)
|
||||||
|
.setRename(!isReadOnly);
|
||||||
|
|
||||||
|
// 构建请求
|
||||||
|
GetWebofficeURLRequest request = new GetWebofficeURLRequest()
|
||||||
|
.setProjectName(immConfig.getProjectName())
|
||||||
|
.setSourceURI(sourceURI)
|
||||||
|
.setFilename(name)
|
||||||
|
.setPermission(permission);
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
GetWebofficeURLResponse response = client.getWebofficeURL(request);
|
||||||
|
|
||||||
|
// 解析响应
|
||||||
|
GetWebofficeURLResponseBody body = response.getBody();
|
||||||
|
|
||||||
|
// 计算过期时间
|
||||||
|
Long expireTime = null;
|
||||||
|
if (body.getAccessTokenExpiredTime() != null) {
|
||||||
|
try {
|
||||||
|
expireTime = Instant.parse(body.getAccessTokenExpiredTime()).toEpochMilli();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("解析过期时间失败:{}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建响应 VO
|
||||||
|
ImmTokenVo tokenVo = ImmTokenVo.builder()
|
||||||
|
.webofficeURL(body.getWebofficeURL())
|
||||||
|
.accessToken(body.getAccessToken())
|
||||||
|
.refreshToken(body.getRefreshToken())
|
||||||
|
.expireTime(expireTime)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
log.info("WebOffice Token 生成成功:webofficeURL={}", maskString(body.getWebofficeURL()));
|
||||||
|
return tokenVo;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("生成 WebOffice Token 失败:{}", e.getMessage(), e);
|
||||||
|
throw new RuntimeException("生成 WebOffice Token 失败:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新 WebOffice Token
|
||||||
|
*
|
||||||
|
* @param accessToken 当前访问凭证
|
||||||
|
* @param refreshToken 刷新凭证
|
||||||
|
* @return 刷新后的 Token 信息
|
||||||
|
*/
|
||||||
|
public ImmTokenVo refreshWebofficeToken(String accessToken, String refreshToken) {
|
||||||
|
try {
|
||||||
|
log.info("刷新 WebOffice Token: accessToken={}, refreshToken={}",
|
||||||
|
maskString(accessToken), maskString(refreshToken));
|
||||||
|
|
||||||
|
// 获取 IMM 客户端
|
||||||
|
Client client = getImmClient();
|
||||||
|
|
||||||
|
// 构建请求
|
||||||
|
RefreshWebofficeTokenRequest request = new RefreshWebofficeTokenRequest()
|
||||||
|
.setProjectName(immConfig.getProjectName())
|
||||||
|
.setAccessToken(accessToken)
|
||||||
|
.setRefreshToken(refreshToken);
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
RefreshWebofficeTokenResponse response = client.refreshWebofficeToken(request);
|
||||||
|
|
||||||
|
// 解析响应
|
||||||
|
RefreshWebofficeTokenResponseBody body = response.getBody();
|
||||||
|
|
||||||
|
// 计算过期时间
|
||||||
|
Long expireTime = null;
|
||||||
|
if (body.getAccessTokenExpiredTime() != null) {
|
||||||
|
try {
|
||||||
|
expireTime = Instant.parse(body.getAccessTokenExpiredTime()).toEpochMilli();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("解析过期时间失败:{}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建响应 VO(刷新 Token 不返回 webofficeURL)
|
||||||
|
ImmTokenVo tokenVo = ImmTokenVo.builder()
|
||||||
|
.accessToken(body.getAccessToken())
|
||||||
|
.refreshToken(body.getRefreshToken())
|
||||||
|
.expireTime(expireTime)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
log.info("WebOffice Token 刷新成功");
|
||||||
|
return tokenVo;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("刷新 WebOffice Token 失败:{}", e.getMessage(), e);
|
||||||
|
throw new RuntimeException("刷新 WebOffice Token 失败:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 IMM 客户端
|
||||||
|
*
|
||||||
|
* @return IMM 客户端实例
|
||||||
|
*/
|
||||||
|
private Client getImmClient() {
|
||||||
|
try {
|
||||||
|
// 配置访问参数
|
||||||
|
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
|
||||||
|
.setAccessKeyId(immConfig.getAccessKeyId())
|
||||||
|
.setAccessKeySecret(immConfig.getAccessKeySecret())
|
||||||
|
.setRegionId(immConfig.getRegion())
|
||||||
|
.setEndpoint(immConfig.getEndpoint());
|
||||||
|
|
||||||
|
// 创建客户端
|
||||||
|
return new Client(config);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("创建 IMM 客户端失败:{}", e.getMessage(), e);
|
||||||
|
throw new RuntimeException("创建 IMM 客户端失败:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 脱敏显示字符串(用于日志)
|
||||||
|
*
|
||||||
|
* @param str 原始字符串
|
||||||
|
* @return 脱敏后的字符串
|
||||||
|
*/
|
||||||
|
private String maskString(String str) {
|
||||||
|
if (str == null || str.length() < 10) {
|
||||||
|
return "***";
|
||||||
|
}
|
||||||
|
return str.substring(0, 3) + "..." + str.substring(str.length() - 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 OSS URL 转换为 IMM 所需的 SourceURI 格式
|
||||||
|
*
|
||||||
|
* @param ossUrl OSS 文件 URL
|
||||||
|
* @return IMM SourceURI 格式
|
||||||
|
*/
|
||||||
|
public String convertOssUrlToSourceURI(String ossUrl) {
|
||||||
|
if (ossUrl == null || ossUrl.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("OSS URL 不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果已经是 oss:// 格式,直接返回
|
||||||
|
if (ossUrl.startsWith("oss://")) {
|
||||||
|
return ossUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从完整 URL 提取 bucket 和 object key
|
||||||
|
// 格式:https://bucket-name.endpoint/object-key
|
||||||
|
try {
|
||||||
|
String url = ossUrl.replace("https://", "");
|
||||||
|
int firstSlash = url.indexOf("/");
|
||||||
|
if (firstSlash == -1) {
|
||||||
|
throw new IllegalArgumentException("无效的 OSS URL 格式:" + ossUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
String bucketAndEndpoint = url.substring(0, firstSlash);
|
||||||
|
String objectKey = url.substring(firstSlash + 1);
|
||||||
|
|
||||||
|
// 提取 bucket 名称(endpoint 之前)
|
||||||
|
String bucket = bucketAndEndpoint.split("\\.")[0];
|
||||||
|
|
||||||
|
// 构建 oss://bucket/object-key 格式
|
||||||
|
return "oss://" + bucket + "/" + objectKey;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("解析 OSS URL 失败:{}", e.getMessage(), e);
|
||||||
|
throw new IllegalArgumentException("无效的 OSS URL 格式:" + ossUrl, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,125 @@
|
|||||||
|
package com.reading.platform.controller;
|
||||||
|
|
||||||
|
import com.reading.platform.common.response.Result;
|
||||||
|
import com.reading.platform.common.util.ImmUtil;
|
||||||
|
import com.reading.platform.dto.response.ImmTokenVo;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 阿里云 IMM(智能媒体服务)控制器
|
||||||
|
* <p>
|
||||||
|
* 提供 WebOffice Token 生成、刷新等接口
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author reading-platform
|
||||||
|
* @since 2026-03-16
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/imm")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Tag(name = "阿里云 IMM 服务", description = "WebOffice 文档预览和编辑相关接口")
|
||||||
|
public class ImmController {
|
||||||
|
|
||||||
|
private final ImmUtil immUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成只读 WebOffice Token
|
||||||
|
* <p>
|
||||||
|
* 用于前端预览文档(PPT、Word、Excel 等),仅支持查看,不支持编辑
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param url OSS 文件路径(如:oss://bucket-name/path/to/file.pptx 或完整 HTTPS URL)
|
||||||
|
* @param name 文件名
|
||||||
|
* @return WebOffice Token 信息
|
||||||
|
*/
|
||||||
|
@GetMapping("/token/readonly")
|
||||||
|
@Operation(summary = "生成只读 WebOffice Token", description = "用于文档预览,仅支持查看")
|
||||||
|
public Result<ImmTokenVo> generateReadOnlyToken(
|
||||||
|
@RequestParam("url") String url,
|
||||||
|
@RequestParam("name") String name) {
|
||||||
|
|
||||||
|
// 将 OSS URL 转换为 IMM 所需的 SourceURI 格式
|
||||||
|
String sourceURI = immUtil.convertOssUrlToSourceURI(url);
|
||||||
|
|
||||||
|
ImmTokenVo tokenVo = immUtil.generateWebofficeTokenReadOnly(sourceURI, name);
|
||||||
|
return Result.success(tokenVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成编辑 WebOffice Token
|
||||||
|
* <p>
|
||||||
|
* 用于前端编辑文档(PPT、Word、Excel 等),支持查看和编辑
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param url OSS 文件路径(如:oss://bucket-name/path/to/file.pptx 或完整 HTTPS URL)
|
||||||
|
* @param name 文件名
|
||||||
|
* @return WebOffice Token 信息
|
||||||
|
*/
|
||||||
|
@GetMapping("/token")
|
||||||
|
@Operation(summary = "生成编辑 WebOffice Token", description = "用于文档编辑,支持查看和修改")
|
||||||
|
public Result<ImmTokenVo> generateEditToken(
|
||||||
|
@RequestParam("url") String url,
|
||||||
|
@RequestParam("name") String name) {
|
||||||
|
|
||||||
|
// 将 OSS URL 转换为 IMM 所需的 SourceURI 格式
|
||||||
|
String sourceURI = immUtil.convertOssUrlToSourceURI(url);
|
||||||
|
|
||||||
|
ImmTokenVo tokenVo = immUtil.generateWebofficeToken(sourceURI, name);
|
||||||
|
return Result.success(tokenVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新 WebOffice Token
|
||||||
|
* <p>
|
||||||
|
* 当 Token 即将过期时,使用 refreshToken 刷新获取新的 Token
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param request 刷新请求,包含 accessToken 和 refreshToken
|
||||||
|
* @return 刷新后的 WebOffice Token 信息
|
||||||
|
*/
|
||||||
|
@PostMapping("/token/refresh")
|
||||||
|
@Operation(summary = "刷新 WebOffice Token", description = "当 Token 即将过期时刷新")
|
||||||
|
public Result<ImmTokenVo> refreshToken(
|
||||||
|
@RequestBody RefreshTokenRequest request) {
|
||||||
|
|
||||||
|
ImmTokenVo tokenVo = immUtil.refreshWebofficeToken(
|
||||||
|
request.getAccessToken(),
|
||||||
|
request.getRefreshToken()
|
||||||
|
);
|
||||||
|
return Result.success(tokenVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新 Token 请求 DTO
|
||||||
|
*/
|
||||||
|
public static class RefreshTokenRequest {
|
||||||
|
/**
|
||||||
|
* 当前访问凭证
|
||||||
|
*/
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新凭证
|
||||||
|
*/
|
||||||
|
private String refreshToken;
|
||||||
|
|
||||||
|
public String getAccessToken() {
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccessToken(String accessToken) {
|
||||||
|
this.accessToken = accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRefreshToken() {
|
||||||
|
return refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRefreshToken(String refreshToken) {
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
package com.reading.platform.dto.response;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 阿里云 IMM WebOffice Token 响应 VO
|
||||||
|
* <p>
|
||||||
|
* 用于前端 WebOffice 文档预览和编辑
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author reading-platform
|
||||||
|
* @since 2026-03-16
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class ImmTokenVo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WebOffice 地址
|
||||||
|
*/
|
||||||
|
private String webofficeURL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 访问凭证
|
||||||
|
*/
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新凭证
|
||||||
|
*/
|
||||||
|
private String refreshToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过期时间(毫秒时间戳)
|
||||||
|
*/
|
||||||
|
private Long expireTime;
|
||||||
|
}
|
||||||
@ -78,7 +78,13 @@ aliyun:
|
|||||||
max-file-size: ${OSS_MAX_FILE_SIZE:10485760}
|
max-file-size: ${OSS_MAX_FILE_SIZE:10485760}
|
||||||
# 前端直传跨域:启动时自动配置 OSS CORS
|
# 前端直传跨域:启动时自动配置 OSS CORS
|
||||||
cors-enabled: ${OSS_CORS_ENABLED:true}
|
cors-enabled: ${OSS_CORS_ENABLED:true}
|
||||||
cors-allowed-origins: ${OSS_CORS_ORIGINS:http://localhost:5173,http://localhost:5174}
|
cors-allowed-origins: ${OSS_CORS_ORIGINS:*}
|
||||||
|
imm:
|
||||||
|
endpoint: ${IMM_ENDPOINT:imm.cn-shenzhen.aliyuncs.com}
|
||||||
|
region: ${IMM_REGION:cn-shenzhen}
|
||||||
|
project-name: ${IMM_PROJECT_NAME:kid-course-platform-doc}
|
||||||
|
access-key-id: ${IMM_ACCESS_KEY_ID:LTAI5tKZhPofbThbSzDSiWoK}
|
||||||
|
access-key-secret: ${IMM_ACCESS_KEY_SECRET:FtcsC7oQX3T0NaChaa9FYq2aoysQFM}
|
||||||
|
|
||||||
# 日志配置(开发环境 - DEBUG 级别)
|
# 日志配置(开发环境 - DEBUG 级别)
|
||||||
logging:
|
logging:
|
||||||
|
|||||||
@ -74,8 +74,15 @@ aliyun:
|
|||||||
access-key-secret: ${OSS_ACCESS_KEY_SECRET:FtcsC7oQX3T0NaChaa9FYq2aoysQFM}
|
access-key-secret: ${OSS_ACCESS_KEY_SECRET:FtcsC7oQX3T0NaChaa9FYq2aoysQFM}
|
||||||
bucket-name: ${OSS_BUCKET_NAME:lesingle-kid-course}
|
bucket-name: ${OSS_BUCKET_NAME:lesingle-kid-course}
|
||||||
max-file-size: ${OSS_MAX_FILE_SIZE:10485760}
|
max-file-size: ${OSS_MAX_FILE_SIZE:10485760}
|
||||||
cors-enabled: ${OSS_CORS_ENABLED:false}
|
# 前端直传跨域:启动时自动配置 OSS CORS
|
||||||
cors-allowed-origins: ${OSS_CORS_ORIGINS:}
|
cors-enabled: ${OSS_CORS_ENABLED:true}
|
||||||
|
cors-allowed-origins: ${OSS_CORS_ORIGINS:*}
|
||||||
|
imm:
|
||||||
|
endpoint: ${IMM_ENDPOINT:imm.cn-shenzhen.aliyuncs.com}
|
||||||
|
region: ${IMM_REGION:cn-shenzhen}
|
||||||
|
project-name: ${IMM_PROJECT_NAME:kid-course-platform-doc}
|
||||||
|
access-key-id: ${IMM_ACCESS_KEY_ID:LTAI5tKZhPofbThbSzDSiWoK}
|
||||||
|
access-key-secret: ${IMM_ACCESS_KEY_SECRET:FtcsC7oQX3T0NaChaa9FYq2aoysQFM}
|
||||||
|
|
||||||
# 日志配置(生产环境 - 降低日志级别)
|
# 日志配置(生产环境 - 降低日志级别)
|
||||||
logging:
|
logging:
|
||||||
|
|||||||
@ -74,6 +74,15 @@ aliyun:
|
|||||||
access-key-secret: ${OSS_ACCESS_KEY_SECRET:FtcsC7oQX3T0NaChaa9FYq2aoysQFM}
|
access-key-secret: ${OSS_ACCESS_KEY_SECRET:FtcsC7oQX3T0NaChaa9FYq2aoysQFM}
|
||||||
bucket-name: ${OSS_BUCKET_NAME:lesingle-kid-course}
|
bucket-name: ${OSS_BUCKET_NAME:lesingle-kid-course}
|
||||||
max-file-size: ${OSS_MAX_FILE_SIZE:10485760}
|
max-file-size: ${OSS_MAX_FILE_SIZE:10485760}
|
||||||
|
# 前端直传跨域:启动时自动配置 OSS CORS
|
||||||
|
cors-enabled: ${OSS_CORS_ENABLED:true}
|
||||||
|
cors-allowed-origins: ${OSS_CORS_ORIGINS:*}
|
||||||
|
imm:
|
||||||
|
endpoint: ${IMM_ENDPOINT:imm.cn-shenzhen.aliyuncs.com}
|
||||||
|
region: ${IMM_REGION:cn-shenzhen}
|
||||||
|
project-name: ${IMM_PROJECT_NAME:kid-course-platform-doc}
|
||||||
|
access-key-id: ${IMM_ACCESS_KEY_ID:LTAI5tKZhPofbThbSzDSiWoK}
|
||||||
|
access-key-secret: ${IMM_ACCESS_KEY_SECRET:FtcsC7oQX3T0NaChaa9FYq2aoysQFM}
|
||||||
|
|
||||||
# 日志配置(测试环境)
|
# 日志配置(测试环境)
|
||||||
logging:
|
logging:
|
||||||
|
|||||||
10
reading-platform-java/test-course.json
Normal file
10
reading-platform-java/test-course.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Test Course 005",
|
||||||
|
"themeId": null,
|
||||||
|
"gradeTags": "[\"class_a\"]",
|
||||||
|
"pictureBookName": "Test Picture Book",
|
||||||
|
"coreContent": "Test Content",
|
||||||
|
"durationMinutes": 25,
|
||||||
|
"domainTags": "[\"social\"]",
|
||||||
|
"introSummary": "Test Summary"
|
||||||
|
}
|
||||||
10
reading-platform-java/test-course2.json
Normal file
10
reading-platform-java/test-course2.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "Test Course 007",
|
||||||
|
"themeId": null,
|
||||||
|
"gradeTags": "[]",
|
||||||
|
"pictureBookName": "Test Picture Book",
|
||||||
|
"coreContent": "Test Content",
|
||||||
|
"durationMinutes": 25,
|
||||||
|
"domainTags": "[]",
|
||||||
|
"introSummary": "Test Summary"
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user