diff --git a/common/common-association/src/main/java/apelet/association/plugin/active/ActivityLiveArchivePlugin.java b/common/common-association/src/main/java/apelet/association/plugin/active/ActivityLiveArchivePlugin.java new file mode 100644 index 0000000..599f699 --- /dev/null +++ b/common/common-association/src/main/java/apelet/association/plugin/active/ActivityLiveArchivePlugin.java @@ -0,0 +1,168 @@ +package apelet.association.plugin.active; + +import apelet.association.plugin.fileLibraryMange.FileLibrayFormPlugin; +import apelet.common.core.exception.MyRuntimeException; +import apelet.common.core.object.ObjectValue; +import apelet.common.core.object.TokenData; +import apelet.common.core.util.ApplicationContextHolder; +import apelet.common.generator.utils.OrmGenDataSourceUtil; +import apelet.common.online.abstractplugin.ExecutePluginParent; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; + +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Date; + +/** + * 活动直播文件归档插件 + * 监听 association_activity 表单的"保存"按钮, + * 将活动直播视频文件(video 字段)归档到文件库表 file_library: + * - video 附件 JSON 数组整体存入 file_library.file_name + * - 自动解析第一个文件的大小与类型,写入 file_size / file_type + * - 归档默认值:分类(classification)4、阅读权限(read_auth)1、 + * 阅读次数(read_count)0、发布状态(publish_status)1 + * - 补齐创建人/创建时间等公共字段,其余字段保持 null + * 注意:每次点击"保存"都会新增一条文件库记录 + */ +public class ActivityLiveArchivePlugin extends ExecutePluginParent { + + /** 文件库目标表 */ + private static final String FILE_LIBRARY_TABLE = "file_library"; + + private final OrmGenDataSourceUtil ormGenDataSourceUtil; + + public ActivityLiveArchivePlugin() { + ormGenDataSourceUtil = ApplicationContextHolder.getBean(OrmGenDataSourceUtil.class); + } + + /** + * 按钮触发事件:检测到"保存"按钮时,将活动直播视频归档到文件库 + * + * @param widgetVariableName 按钮标识 + * @param objectValue 当前表单数据对象 + */ + @Override + public void buttonTriggered(String widgetVariableName, ObjectValue objectValue) { + super.buttonTriggered(widgetVariableName, objectValue); + // 仅响应"保存"按钮 + if (!"保存".equals(widgetVariableName)) { + return; + } + saveLiveVideoToFileLibrary(objectValue); + } + + /** + * 保存活动直播视频到文件库表 file_library + * 视频字段为空时直接跳过,不写入任何记录 + * + * @param objectValue 活动表单数据对象 + */ + private void saveLiveVideoToFileLibrary(ObjectValue objectValue) { + // 读取活动直播视频字段(association_activity.video),为空则跳过 + Object videoObj = objectValue.get("video"); + if (videoObj == null) { + return; + } + String videoText = videoObj.toString(); + if (videoText.isEmpty()) { + return; + } + // 解析附件 JSON 数组 + JSONArray fileArray; + try { + fileArray = JSON.parseArray(videoText); + } catch (Exception e) { + fileArray = null; + } + if (fileArray == null || fileArray.isEmpty()) { + return; + } + // file_size / file_type 为单值字段,取第一个文件的大小与类型 + String fileType = null; + String fileSize = null; + JSONObject firstFile = fileArray.getJSONObject(0); + if (firstFile != null) { + fileType = resolveFileType(firstFile.getString("filename")); + fileSize = resolveFileSize(firstFile); + } + // 当前登录用户与当前时间(公共字段) + TokenData tokenData = TokenData.takeFromRequest(); + Long userId = tokenData == null ? null : tokenData.getUserId(); + Date now = new Date(); + // 组装 file_library 记录 + ObjectValue record = new ObjectValue(FILE_LIBRARY_TABLE); + record.put("file_name", videoText); + record.put("file_type", fileType); + record.put("file_size", fileSize); + // 活动直播归档默认值:分类 4、阅读权限 1、阅读次数 0、发布状态 1 + record.put("classification", "4"); + record.put("read_auth", "1"); + record.put("read_count", 0); + record.put("publish_status", "1"); + // 公共字段 + record.put("create_user_id", userId); + record.put("create_time", now); + record.put("update_user_id", userId); + record.put("update_time", now); + record.put("deleted_flag", 1); + // 插入文件库表,主键 id 由框架自动生成 + try { + ormGenDataSourceUtil.addNew(FILE_LIBRARY_TABLE, record); + } catch (Exception e) { + throw new MyRuntimeException("保存活动直播文件到文件库失败:" + e.getMessage()); + } + } + + /** + * 通过 HEAD 请求获取 OSS 文件大小,并格式化为 KB/MB 展示字符串 + * 获取失败返回 null,不阻塞保存流程 + * + * @param file 附件 JSON 中的单个文件对象 + * @return 格式化后的文件大小(如 "1.6 MB"),失败返回 null + */ + private String resolveFileSize(JSONObject file) { + String baseUrl = file.getString("baseUrl"); + String uploadPath = file.getString("uploadPath"); + String filename = file.getString("filename"); + if (baseUrl == null || uploadPath == null || filename == null) { + return null; + } + String fullUrl = baseUrl + "/" + uploadPath + "/" + filename; + HttpURLConnection connection = null; + try { + URL url = new URL(fullUrl); + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("HEAD"); + connection.setConnectTimeout(5000); + connection.setReadTimeout(5000); + connection.connect(); + long fileSize = connection.getContentLengthLong(); + if (fileSize > 0) { + return FileLibrayFormPlugin.formatFileSize(fileSize); + } + } catch (Exception e) { + // 获取大小失败时返回 null,不影响保存 + System.out.println("获取附件文件大小失败:" + fullUrl + "," + e.getMessage()); + } finally { + if (connection != null) { + connection.disconnect(); + } + } + return null; + } + + /** + * 从文件名提取扩展名作为文件类型,如 "直播回放.mp4" -> "mp4" + * + * @param fileName 文件名 + * @return 文件扩展名,无法识别返回 null + */ + private String resolveFileType(String fileName) { + if (fileName == null || fileName.isEmpty() || !fileName.contains(".")) { + return null; + } + return fileName.substring(fileName.lastIndexOf(".") + 1); + } +}